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 editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction::Direction;
   56pub use editor_settings::{
   57    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   58    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   59};
   60pub use editor_settings_controls::*;
   61pub use element::{
   62    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, ParticipantIndex, parse_zed_link};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  125    DiagnosticEntry, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  126    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  127    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  152    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  153    ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  164};
  165use rand::seq::SliceRandom;
  166use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  167use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  168use selections_collection::{
  169    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  170};
  171use serde::{Deserialize, Serialize};
  172use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  173use smallvec::{SmallVec, smallvec};
  174use snippet::Snippet;
  175use std::{
  176    any::{Any, TypeId},
  177    borrow::Cow,
  178    cell::{OnceCell, RefCell},
  179    cmp::{self, Ordering, Reverse},
  180    iter::{self, Peekable},
  181    mem,
  182    num::NonZeroU32,
  183    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  184    path::{Path, PathBuf},
  185    rc::Rc,
  186    sync::Arc,
  187    time::{Duration, Instant},
  188};
  189use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  190use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  191use theme::{
  192    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  193    observe_buffer_font_size_adjustment,
  194};
  195use ui::{
  196    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  197    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  198};
  199use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  200use workspace::{
  201    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  202    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  203    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  204    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  205    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  206    searchable::SearchEvent,
  207};
  208
  209use crate::{
  210    code_context_menus::CompletionsMenuSource,
  211    editor_settings::MultiCursorModifier,
  212    hover_links::{find_url, find_url_from_range},
  213    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  214};
  215
  216pub const FILE_HEADER_HEIGHT: u32 = 2;
  217pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  218const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  219const MAX_LINE_LEN: usize = 1024;
  220const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  221const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  222pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  223#[doc(hidden)]
  224pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  225pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  226
  227pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  229pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  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(usize),
  283    DebuggerValue(usize),
  284    // LSP
  285    Hint(usize),
  286    Color(usize),
  287}
  288
  289impl InlayId {
  290    fn id(&self) -> usize {
  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<DiagnosticEntry<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<DiagnosticEntry<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 {
  642        target: Anchor,
  643        snapshot: BufferSnapshot,
  644    },
  645}
  646
  647struct EditPredictionState {
  648    inlay_ids: Vec<InlayId>,
  649    completion: EditPrediction,
  650    completion_id: Option<SharedString>,
  651    invalidation_range: Range<Anchor>,
  652}
  653
  654enum EditPredictionSettings {
  655    Disabled,
  656    Enabled {
  657        show_in_menu: bool,
  658        preview_requires_modifier: bool,
  659    },
  660}
  661
  662enum EditPredictionHighlight {}
  663
  664#[derive(Debug, Clone)]
  665struct InlineDiagnostic {
  666    message: SharedString,
  667    group_id: usize,
  668    is_primary: bool,
  669    start: Point,
  670    severity: lsp::DiagnosticSeverity,
  671}
  672
  673pub enum MenuEditPredictionsPolicy {
  674    Never,
  675    ByProvider,
  676}
  677
  678pub enum EditPredictionPreview {
  679    /// Modifier is not pressed
  680    Inactive { released_too_fast: bool },
  681    /// Modifier pressed
  682    Active {
  683        since: Instant,
  684        previous_scroll_position: Option<ScrollAnchor>,
  685    },
  686}
  687
  688impl EditPredictionPreview {
  689    pub fn released_too_fast(&self) -> bool {
  690        match self {
  691            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  692            EditPredictionPreview::Active { .. } => false,
  693        }
  694    }
  695
  696    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  697        if let EditPredictionPreview::Active {
  698            previous_scroll_position,
  699            ..
  700        } = self
  701        {
  702            *previous_scroll_position = scroll_position;
  703        }
  704    }
  705}
  706
  707pub struct ContextMenuOptions {
  708    pub min_entries_visible: usize,
  709    pub max_entries_visible: usize,
  710    pub placement: Option<ContextMenuPlacement>,
  711}
  712
  713#[derive(Debug, Clone, PartialEq, Eq)]
  714pub enum ContextMenuPlacement {
  715    Above,
  716    Below,
  717}
  718
  719#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  720struct EditorActionId(usize);
  721
  722impl EditorActionId {
  723    pub fn post_inc(&mut self) -> Self {
  724        let answer = self.0;
  725
  726        *self = Self(answer + 1);
  727
  728        Self(answer)
  729    }
  730}
  731
  732// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  733// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  734
  735type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  736type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  737
  738#[derive(Default)]
  739struct ScrollbarMarkerState {
  740    scrollbar_size: Size<Pixels>,
  741    dirty: bool,
  742    markers: Arc<[PaintQuad]>,
  743    pending_refresh: Option<Task<Result<()>>>,
  744}
  745
  746impl ScrollbarMarkerState {
  747    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  748        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  749    }
  750}
  751
  752#[derive(Clone, Copy, PartialEq, Eq)]
  753pub enum MinimapVisibility {
  754    Disabled,
  755    Enabled {
  756        /// The configuration currently present in the users settings.
  757        setting_configuration: bool,
  758        /// Whether to override the currently set visibility from the users setting.
  759        toggle_override: bool,
  760    },
  761}
  762
  763impl MinimapVisibility {
  764    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  765        if mode.is_full() {
  766            Self::Enabled {
  767                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  768                toggle_override: false,
  769            }
  770        } else {
  771            Self::Disabled
  772        }
  773    }
  774
  775    fn hidden(&self) -> Self {
  776        match *self {
  777            Self::Enabled {
  778                setting_configuration,
  779                ..
  780            } => Self::Enabled {
  781                setting_configuration,
  782                toggle_override: setting_configuration,
  783            },
  784            Self::Disabled => Self::Disabled,
  785        }
  786    }
  787
  788    fn disabled(&self) -> bool {
  789        matches!(*self, Self::Disabled)
  790    }
  791
  792    fn settings_visibility(&self) -> bool {
  793        match *self {
  794            Self::Enabled {
  795                setting_configuration,
  796                ..
  797            } => setting_configuration,
  798            _ => false,
  799        }
  800    }
  801
  802    fn visible(&self) -> bool {
  803        match *self {
  804            Self::Enabled {
  805                setting_configuration,
  806                toggle_override,
  807            } => setting_configuration ^ toggle_override,
  808            _ => false,
  809        }
  810    }
  811
  812    fn toggle_visibility(&self) -> Self {
  813        match *self {
  814            Self::Enabled {
  815                toggle_override,
  816                setting_configuration,
  817            } => Self::Enabled {
  818                setting_configuration,
  819                toggle_override: !toggle_override,
  820            },
  821            Self::Disabled => Self::Disabled,
  822        }
  823    }
  824}
  825
  826#[derive(Clone, Debug)]
  827struct RunnableTasks {
  828    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  829    offset: multi_buffer::Anchor,
  830    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  831    column: u32,
  832    // Values of all named captures, including those starting with '_'
  833    extra_variables: HashMap<String, String>,
  834    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  835    context_range: Range<BufferOffset>,
  836}
  837
  838impl RunnableTasks {
  839    fn resolve<'a>(
  840        &'a self,
  841        cx: &'a task::TaskContext,
  842    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  843        self.templates.iter().filter_map(|(kind, template)| {
  844            template
  845                .resolve_task(&kind.to_id_base(), cx)
  846                .map(|task| (kind.clone(), task))
  847        })
  848    }
  849}
  850
  851#[derive(Clone)]
  852pub struct ResolvedTasks {
  853    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  854    position: Anchor,
  855}
  856
  857#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  858struct BufferOffset(usize);
  859
  860/// Addons allow storing per-editor state in other crates (e.g. Vim)
  861pub trait Addon: 'static {
  862    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  863
  864    fn render_buffer_header_controls(
  865        &self,
  866        _: &ExcerptInfo,
  867        _: &Window,
  868        _: &App,
  869    ) -> Option<AnyElement> {
  870        None
  871    }
  872
  873    fn to_any(&self) -> &dyn std::any::Any;
  874
  875    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  876        None
  877    }
  878}
  879
  880struct ChangeLocation {
  881    current: Option<Vec<Anchor>>,
  882    original: Vec<Anchor>,
  883}
  884impl ChangeLocation {
  885    fn locations(&self) -> &[Anchor] {
  886        self.current.as_ref().unwrap_or(&self.original)
  887    }
  888}
  889
  890/// A set of caret positions, registered when the editor was edited.
  891pub struct ChangeList {
  892    changes: Vec<ChangeLocation>,
  893    /// Currently "selected" change.
  894    position: Option<usize>,
  895}
  896
  897impl ChangeList {
  898    pub fn new() -> Self {
  899        Self {
  900            changes: Vec::new(),
  901            position: None,
  902        }
  903    }
  904
  905    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  906    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  907    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  908        if self.changes.is_empty() {
  909            return None;
  910        }
  911
  912        let prev = self.position.unwrap_or(self.changes.len());
  913        let next = if direction == Direction::Prev {
  914            prev.saturating_sub(count)
  915        } else {
  916            (prev + count).min(self.changes.len() - 1)
  917        };
  918        self.position = Some(next);
  919        self.changes.get(next).map(|change| change.locations())
  920    }
  921
  922    /// Adds a new change to the list, resetting the change list position.
  923    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  924        self.position.take();
  925        if let Some(last) = self.changes.last_mut()
  926            && group
  927        {
  928            last.current = Some(new_positions)
  929        } else {
  930            self.changes.push(ChangeLocation {
  931                original: new_positions,
  932                current: None,
  933            });
  934        }
  935    }
  936
  937    pub fn last(&self) -> Option<&[Anchor]> {
  938        self.changes.last().map(|change| change.locations())
  939    }
  940
  941    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  942        self.changes.last().map(|change| change.original.as_slice())
  943    }
  944
  945    pub fn invert_last_group(&mut self) {
  946        if let Some(last) = self.changes.last_mut()
  947            && let Some(current) = last.current.as_mut()
  948        {
  949            mem::swap(&mut last.original, current);
  950        }
  951    }
  952}
  953
  954#[derive(Clone)]
  955struct InlineBlamePopoverState {
  956    scroll_handle: ScrollHandle,
  957    commit_message: Option<ParsedCommitMessage>,
  958    markdown: Entity<Markdown>,
  959}
  960
  961struct InlineBlamePopover {
  962    position: gpui::Point<Pixels>,
  963    hide_task: Option<Task<()>>,
  964    popover_bounds: Option<Bounds<Pixels>>,
  965    popover_state: InlineBlamePopoverState,
  966    keyboard_grace: bool,
  967}
  968
  969enum SelectionDragState {
  970    /// State when no drag related activity is detected.
  971    None,
  972    /// State when the mouse is down on a selection that is about to be dragged.
  973    ReadyToDrag {
  974        selection: Selection<Anchor>,
  975        click_position: gpui::Point<Pixels>,
  976        mouse_down_time: Instant,
  977    },
  978    /// State when the mouse is dragging the selection in the editor.
  979    Dragging {
  980        selection: Selection<Anchor>,
  981        drop_cursor: Selection<Anchor>,
  982        hide_drop_cursor: bool,
  983    },
  984}
  985
  986enum ColumnarSelectionState {
  987    FromMouse {
  988        selection_tail: Anchor,
  989        display_point: Option<DisplayPoint>,
  990    },
  991    FromSelection {
  992        selection_tail: Anchor,
  993    },
  994}
  995
  996/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  997/// a breakpoint on them.
  998#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  999struct PhantomBreakpointIndicator {
 1000    display_row: DisplayRow,
 1001    /// There's a small debounce between hovering over the line and showing the indicator.
 1002    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1003    is_active: bool,
 1004    collides_with_existing_breakpoint: bool,
 1005}
 1006
 1007/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1008///
 1009/// See the [module level documentation](self) for more information.
 1010pub struct Editor {
 1011    focus_handle: FocusHandle,
 1012    last_focused_descendant: Option<WeakFocusHandle>,
 1013    /// The text buffer being edited
 1014    buffer: Entity<MultiBuffer>,
 1015    /// Map of how text in the buffer should be displayed.
 1016    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1017    pub display_map: Entity<DisplayMap>,
 1018    placeholder_display_map: Option<Entity<DisplayMap>>,
 1019    pub selections: SelectionsCollection,
 1020    pub scroll_manager: ScrollManager,
 1021    /// When inline assist editors are linked, they all render cursors because
 1022    /// typing enters text into each of them, even the ones that aren't focused.
 1023    pub(crate) show_cursor_when_unfocused: bool,
 1024    columnar_selection_state: Option<ColumnarSelectionState>,
 1025    add_selections_state: Option<AddSelectionsState>,
 1026    select_next_state: Option<SelectNextState>,
 1027    select_prev_state: Option<SelectNextState>,
 1028    selection_history: SelectionHistory,
 1029    defer_selection_effects: bool,
 1030    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1031    autoclose_regions: Vec<AutocloseRegion>,
 1032    snippet_stack: InvalidationStack<SnippetState>,
 1033    select_syntax_node_history: SelectSyntaxNodeHistory,
 1034    ime_transaction: Option<TransactionId>,
 1035    pub diagnostics_max_severity: DiagnosticSeverity,
 1036    active_diagnostics: ActiveDiagnostic,
 1037    show_inline_diagnostics: bool,
 1038    inline_diagnostics_update: Task<()>,
 1039    inline_diagnostics_enabled: bool,
 1040    diagnostics_enabled: bool,
 1041    word_completions_enabled: bool,
 1042    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1043    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1044    hard_wrap: Option<usize>,
 1045    project: Option<Entity<Project>>,
 1046    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1047    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1048    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1049    blink_manager: Entity<BlinkManager>,
 1050    show_cursor_names: bool,
 1051    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1052    pub show_local_selections: bool,
 1053    mode: EditorMode,
 1054    show_breadcrumbs: bool,
 1055    show_gutter: bool,
 1056    show_scrollbars: ScrollbarAxes,
 1057    minimap_visibility: MinimapVisibility,
 1058    offset_content: bool,
 1059    disable_expand_excerpt_buttons: bool,
 1060    show_line_numbers: Option<bool>,
 1061    use_relative_line_numbers: Option<bool>,
 1062    show_git_diff_gutter: Option<bool>,
 1063    show_code_actions: Option<bool>,
 1064    show_runnables: Option<bool>,
 1065    show_breakpoints: Option<bool>,
 1066    show_wrap_guides: Option<bool>,
 1067    show_indent_guides: Option<bool>,
 1068    highlight_order: usize,
 1069    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1070    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1071    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1072    scrollbar_marker_state: ScrollbarMarkerState,
 1073    active_indent_guides_state: ActiveIndentGuidesState,
 1074    nav_history: Option<ItemNavHistory>,
 1075    context_menu: RefCell<Option<CodeContextMenu>>,
 1076    context_menu_options: Option<ContextMenuOptions>,
 1077    mouse_context_menu: Option<MouseContextMenu>,
 1078    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1079    inline_blame_popover: Option<InlineBlamePopover>,
 1080    inline_blame_popover_show_task: Option<Task<()>>,
 1081    signature_help_state: SignatureHelpState,
 1082    auto_signature_help: Option<bool>,
 1083    find_all_references_task_sources: Vec<Anchor>,
 1084    next_completion_id: CompletionId,
 1085    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1086    code_actions_task: Option<Task<Result<()>>>,
 1087    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1088    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1089    document_highlights_task: Option<Task<()>>,
 1090    linked_editing_range_task: Option<Task<Option<()>>>,
 1091    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1092    pending_rename: Option<RenameState>,
 1093    searchable: bool,
 1094    cursor_shape: CursorShape,
 1095    current_line_highlight: Option<CurrentLineHighlight>,
 1096    collapse_matches: bool,
 1097    autoindent_mode: Option<AutoindentMode>,
 1098    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1099    input_enabled: bool,
 1100    use_modal_editing: bool,
 1101    read_only: bool,
 1102    leader_id: Option<CollaboratorId>,
 1103    remote_id: Option<ViewId>,
 1104    pub hover_state: HoverState,
 1105    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1106    gutter_hovered: bool,
 1107    hovered_link_state: Option<HoveredLinkState>,
 1108    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1109    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1110    active_edit_prediction: Option<EditPredictionState>,
 1111    /// Used to prevent flickering as the user types while the menu is open
 1112    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1113    edit_prediction_settings: EditPredictionSettings,
 1114    edit_predictions_hidden_for_vim_mode: bool,
 1115    show_edit_predictions_override: Option<bool>,
 1116    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1117    edit_prediction_preview: EditPredictionPreview,
 1118    edit_prediction_indent_conflict: bool,
 1119    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1120    inlay_hint_cache: InlayHintCache,
 1121    next_inlay_id: usize,
 1122    _subscriptions: Vec<Subscription>,
 1123    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1124    gutter_dimensions: GutterDimensions,
 1125    style: Option<EditorStyle>,
 1126    text_style_refinement: Option<TextStyleRefinement>,
 1127    next_editor_action_id: EditorActionId,
 1128    editor_actions: Rc<
 1129        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1130    >,
 1131    use_autoclose: bool,
 1132    use_auto_surround: bool,
 1133    auto_replace_emoji_shortcode: bool,
 1134    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1135    show_git_blame_gutter: bool,
 1136    show_git_blame_inline: bool,
 1137    show_git_blame_inline_delay_task: Option<Task<()>>,
 1138    git_blame_inline_enabled: bool,
 1139    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1140    serialize_dirty_buffers: bool,
 1141    show_selection_menu: Option<bool>,
 1142    blame: Option<Entity<GitBlame>>,
 1143    blame_subscription: Option<Subscription>,
 1144    custom_context_menu: Option<
 1145        Box<
 1146            dyn 'static
 1147                + Fn(
 1148                    &mut Self,
 1149                    DisplayPoint,
 1150                    &mut Window,
 1151                    &mut Context<Self>,
 1152                ) -> Option<Entity<ui::ContextMenu>>,
 1153        >,
 1154    >,
 1155    last_bounds: Option<Bounds<Pixels>>,
 1156    last_position_map: Option<Rc<PositionMap>>,
 1157    expect_bounds_change: Option<Bounds<Pixels>>,
 1158    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1159    tasks_update_task: Option<Task<()>>,
 1160    breakpoint_store: Option<Entity<BreakpointStore>>,
 1161    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1162    hovered_diff_hunk_row: Option<DisplayRow>,
 1163    pull_diagnostics_task: Task<()>,
 1164    in_project_search: bool,
 1165    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1166    breadcrumb_header: Option<String>,
 1167    focused_block: Option<FocusedBlock>,
 1168    next_scroll_position: NextScrollCursorCenterTopBottom,
 1169    addons: HashMap<TypeId, Box<dyn Addon>>,
 1170    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1171    load_diff_task: Option<Shared<Task<()>>>,
 1172    /// Whether we are temporarily displaying a diff other than git's
 1173    temporary_diff_override: bool,
 1174    selection_mark_mode: bool,
 1175    toggle_fold_multiple_buffers: Task<()>,
 1176    _scroll_cursor_center_top_bottom_task: Task<()>,
 1177    serialize_selections: Task<()>,
 1178    serialize_folds: Task<()>,
 1179    mouse_cursor_hidden: bool,
 1180    minimap: Option<Entity<Self>>,
 1181    hide_mouse_mode: HideMouseMode,
 1182    pub change_list: ChangeList,
 1183    inline_value_cache: InlineValueCache,
 1184    selection_drag_state: SelectionDragState,
 1185    next_color_inlay_id: usize,
 1186    colors: Option<LspColorData>,
 1187    folding_newlines: Task<()>,
 1188    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1189}
 1190
 1191#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1192enum NextScrollCursorCenterTopBottom {
 1193    #[default]
 1194    Center,
 1195    Top,
 1196    Bottom,
 1197}
 1198
 1199impl NextScrollCursorCenterTopBottom {
 1200    fn next(&self) -> Self {
 1201        match self {
 1202            Self::Center => Self::Top,
 1203            Self::Top => Self::Bottom,
 1204            Self::Bottom => Self::Center,
 1205        }
 1206    }
 1207}
 1208
 1209#[derive(Clone)]
 1210pub struct EditorSnapshot {
 1211    pub mode: EditorMode,
 1212    show_gutter: bool,
 1213    show_line_numbers: Option<bool>,
 1214    show_git_diff_gutter: Option<bool>,
 1215    show_code_actions: Option<bool>,
 1216    show_runnables: Option<bool>,
 1217    show_breakpoints: Option<bool>,
 1218    git_blame_gutter_max_author_length: Option<usize>,
 1219    pub display_snapshot: DisplaySnapshot,
 1220    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1221    is_focused: bool,
 1222    scroll_anchor: ScrollAnchor,
 1223    ongoing_scroll: OngoingScroll,
 1224    current_line_highlight: CurrentLineHighlight,
 1225    gutter_hovered: bool,
 1226}
 1227
 1228#[derive(Default, Debug, Clone, Copy)]
 1229pub struct GutterDimensions {
 1230    pub left_padding: Pixels,
 1231    pub right_padding: Pixels,
 1232    pub width: Pixels,
 1233    pub margin: Pixels,
 1234    pub git_blame_entries_width: Option<Pixels>,
 1235}
 1236
 1237impl GutterDimensions {
 1238    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1239        Self {
 1240            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1241            ..Default::default()
 1242        }
 1243    }
 1244
 1245    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1246        -cx.text_system().descent(font_id, font_size)
 1247    }
 1248    /// The full width of the space taken up by the gutter.
 1249    pub fn full_width(&self) -> Pixels {
 1250        self.margin + self.width
 1251    }
 1252
 1253    /// The width of the space reserved for the fold indicators,
 1254    /// use alongside 'justify_end' and `gutter_width` to
 1255    /// right align content with the line numbers
 1256    pub fn fold_area_width(&self) -> Pixels {
 1257        self.margin + self.right_padding
 1258    }
 1259}
 1260
 1261struct CharacterDimensions {
 1262    em_width: Pixels,
 1263    em_advance: Pixels,
 1264    line_height: Pixels,
 1265}
 1266
 1267#[derive(Debug)]
 1268pub struct RemoteSelection {
 1269    pub replica_id: ReplicaId,
 1270    pub selection: Selection<Anchor>,
 1271    pub cursor_shape: CursorShape,
 1272    pub collaborator_id: CollaboratorId,
 1273    pub line_mode: bool,
 1274    pub user_name: Option<SharedString>,
 1275    pub color: PlayerColor,
 1276}
 1277
 1278#[derive(Clone, Debug)]
 1279struct SelectionHistoryEntry {
 1280    selections: Arc<[Selection<Anchor>]>,
 1281    select_next_state: Option<SelectNextState>,
 1282    select_prev_state: Option<SelectNextState>,
 1283    add_selections_state: Option<AddSelectionsState>,
 1284}
 1285
 1286#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1287enum SelectionHistoryMode {
 1288    Normal,
 1289    Undoing,
 1290    Redoing,
 1291    Skipping,
 1292}
 1293
 1294#[derive(Clone, PartialEq, Eq, Hash)]
 1295struct HoveredCursor {
 1296    replica_id: u16,
 1297    selection_id: usize,
 1298}
 1299
 1300impl Default for SelectionHistoryMode {
 1301    fn default() -> Self {
 1302        Self::Normal
 1303    }
 1304}
 1305
 1306#[derive(Debug)]
 1307/// SelectionEffects controls the side-effects of updating the selection.
 1308///
 1309/// The default behaviour does "what you mostly want":
 1310/// - it pushes to the nav history if the cursor moved by >10 lines
 1311/// - it re-triggers completion requests
 1312/// - it scrolls to fit
 1313///
 1314/// You might want to modify these behaviours. For example when doing a "jump"
 1315/// like go to definition, we always want to add to nav history; but when scrolling
 1316/// in vim mode we never do.
 1317///
 1318/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1319/// move.
 1320#[derive(Clone)]
 1321pub struct SelectionEffects {
 1322    nav_history: Option<bool>,
 1323    completions: bool,
 1324    scroll: Option<Autoscroll>,
 1325}
 1326
 1327impl Default for SelectionEffects {
 1328    fn default() -> Self {
 1329        Self {
 1330            nav_history: None,
 1331            completions: true,
 1332            scroll: Some(Autoscroll::fit()),
 1333        }
 1334    }
 1335}
 1336impl SelectionEffects {
 1337    pub fn scroll(scroll: Autoscroll) -> Self {
 1338        Self {
 1339            scroll: Some(scroll),
 1340            ..Default::default()
 1341        }
 1342    }
 1343
 1344    pub fn no_scroll() -> Self {
 1345        Self {
 1346            scroll: None,
 1347            ..Default::default()
 1348        }
 1349    }
 1350
 1351    pub fn completions(self, completions: bool) -> Self {
 1352        Self {
 1353            completions,
 1354            ..self
 1355        }
 1356    }
 1357
 1358    pub fn nav_history(self, nav_history: bool) -> Self {
 1359        Self {
 1360            nav_history: Some(nav_history),
 1361            ..self
 1362        }
 1363    }
 1364}
 1365
 1366struct DeferredSelectionEffectsState {
 1367    changed: bool,
 1368    effects: SelectionEffects,
 1369    old_cursor_position: Anchor,
 1370    history_entry: SelectionHistoryEntry,
 1371}
 1372
 1373#[derive(Default)]
 1374struct SelectionHistory {
 1375    #[allow(clippy::type_complexity)]
 1376    selections_by_transaction:
 1377        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1378    mode: SelectionHistoryMode,
 1379    undo_stack: VecDeque<SelectionHistoryEntry>,
 1380    redo_stack: VecDeque<SelectionHistoryEntry>,
 1381}
 1382
 1383impl SelectionHistory {
 1384    #[track_caller]
 1385    fn insert_transaction(
 1386        &mut self,
 1387        transaction_id: TransactionId,
 1388        selections: Arc<[Selection<Anchor>]>,
 1389    ) {
 1390        if selections.is_empty() {
 1391            log::error!(
 1392                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1393                std::panic::Location::caller()
 1394            );
 1395            return;
 1396        }
 1397        self.selections_by_transaction
 1398            .insert(transaction_id, (selections, None));
 1399    }
 1400
 1401    #[allow(clippy::type_complexity)]
 1402    fn transaction(
 1403        &self,
 1404        transaction_id: TransactionId,
 1405    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1406        self.selections_by_transaction.get(&transaction_id)
 1407    }
 1408
 1409    #[allow(clippy::type_complexity)]
 1410    fn transaction_mut(
 1411        &mut self,
 1412        transaction_id: TransactionId,
 1413    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1414        self.selections_by_transaction.get_mut(&transaction_id)
 1415    }
 1416
 1417    fn push(&mut self, entry: SelectionHistoryEntry) {
 1418        if !entry.selections.is_empty() {
 1419            match self.mode {
 1420                SelectionHistoryMode::Normal => {
 1421                    self.push_undo(entry);
 1422                    self.redo_stack.clear();
 1423                }
 1424                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1425                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1426                SelectionHistoryMode::Skipping => {}
 1427            }
 1428        }
 1429    }
 1430
 1431    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1432        if self
 1433            .undo_stack
 1434            .back()
 1435            .is_none_or(|e| e.selections != entry.selections)
 1436        {
 1437            self.undo_stack.push_back(entry);
 1438            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1439                self.undo_stack.pop_front();
 1440            }
 1441        }
 1442    }
 1443
 1444    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1445        if self
 1446            .redo_stack
 1447            .back()
 1448            .is_none_or(|e| e.selections != entry.selections)
 1449        {
 1450            self.redo_stack.push_back(entry);
 1451            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1452                self.redo_stack.pop_front();
 1453            }
 1454        }
 1455    }
 1456}
 1457
 1458#[derive(Clone, Copy)]
 1459pub struct RowHighlightOptions {
 1460    pub autoscroll: bool,
 1461    pub include_gutter: bool,
 1462}
 1463
 1464impl Default for RowHighlightOptions {
 1465    fn default() -> Self {
 1466        Self {
 1467            autoscroll: Default::default(),
 1468            include_gutter: true,
 1469        }
 1470    }
 1471}
 1472
 1473struct RowHighlight {
 1474    index: usize,
 1475    range: Range<Anchor>,
 1476    color: Hsla,
 1477    options: RowHighlightOptions,
 1478    type_id: TypeId,
 1479}
 1480
 1481#[derive(Clone, Debug)]
 1482struct AddSelectionsState {
 1483    groups: Vec<AddSelectionsGroup>,
 1484}
 1485
 1486#[derive(Clone, Debug)]
 1487struct AddSelectionsGroup {
 1488    above: bool,
 1489    stack: Vec<usize>,
 1490}
 1491
 1492#[derive(Clone)]
 1493struct SelectNextState {
 1494    query: AhoCorasick,
 1495    wordwise: bool,
 1496    done: bool,
 1497}
 1498
 1499impl std::fmt::Debug for SelectNextState {
 1500    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1501        f.debug_struct(std::any::type_name::<Self>())
 1502            .field("wordwise", &self.wordwise)
 1503            .field("done", &self.done)
 1504            .finish()
 1505    }
 1506}
 1507
 1508#[derive(Debug)]
 1509struct AutocloseRegion {
 1510    selection_id: usize,
 1511    range: Range<Anchor>,
 1512    pair: BracketPair,
 1513}
 1514
 1515#[derive(Debug)]
 1516struct SnippetState {
 1517    ranges: Vec<Vec<Range<Anchor>>>,
 1518    active_index: usize,
 1519    choices: Vec<Option<Vec<String>>>,
 1520}
 1521
 1522#[doc(hidden)]
 1523pub struct RenameState {
 1524    pub range: Range<Anchor>,
 1525    pub old_name: Arc<str>,
 1526    pub editor: Entity<Editor>,
 1527    block_id: CustomBlockId,
 1528}
 1529
 1530struct InvalidationStack<T>(Vec<T>);
 1531
 1532struct RegisteredEditPredictionProvider {
 1533    provider: Arc<dyn EditPredictionProviderHandle>,
 1534    _subscription: Subscription,
 1535}
 1536
 1537#[derive(Debug, PartialEq, Eq)]
 1538pub struct ActiveDiagnosticGroup {
 1539    pub active_range: Range<Anchor>,
 1540    pub active_message: String,
 1541    pub group_id: usize,
 1542    pub blocks: HashSet<CustomBlockId>,
 1543}
 1544
 1545#[derive(Debug, PartialEq, Eq)]
 1546
 1547pub(crate) enum ActiveDiagnostic {
 1548    None,
 1549    All,
 1550    Group(ActiveDiagnosticGroup),
 1551}
 1552
 1553#[derive(Serialize, Deserialize, Clone, Debug)]
 1554pub struct ClipboardSelection {
 1555    /// The number of bytes in this selection.
 1556    pub len: usize,
 1557    /// Whether this was a full-line selection.
 1558    pub is_entire_line: bool,
 1559    /// The indentation of the first line when this content was originally copied.
 1560    pub first_line_indent: u32,
 1561}
 1562
 1563// selections, scroll behavior, was newest selection reversed
 1564type SelectSyntaxNodeHistoryState = (
 1565    Box<[Selection<usize>]>,
 1566    SelectSyntaxNodeScrollBehavior,
 1567    bool,
 1568);
 1569
 1570#[derive(Default)]
 1571struct SelectSyntaxNodeHistory {
 1572    stack: Vec<SelectSyntaxNodeHistoryState>,
 1573    // disable temporarily to allow changing selections without losing the stack
 1574    pub disable_clearing: bool,
 1575}
 1576
 1577impl SelectSyntaxNodeHistory {
 1578    pub fn try_clear(&mut self) {
 1579        if !self.disable_clearing {
 1580            self.stack.clear();
 1581        }
 1582    }
 1583
 1584    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1585        self.stack.push(selection);
 1586    }
 1587
 1588    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1589        self.stack.pop()
 1590    }
 1591}
 1592
 1593enum SelectSyntaxNodeScrollBehavior {
 1594    CursorTop,
 1595    FitSelection,
 1596    CursorBottom,
 1597}
 1598
 1599#[derive(Debug)]
 1600pub(crate) struct NavigationData {
 1601    cursor_anchor: Anchor,
 1602    cursor_position: Point,
 1603    scroll_anchor: ScrollAnchor,
 1604    scroll_top_row: u32,
 1605}
 1606
 1607#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1608pub enum GotoDefinitionKind {
 1609    Symbol,
 1610    Declaration,
 1611    Type,
 1612    Implementation,
 1613}
 1614
 1615#[derive(Debug, Clone)]
 1616enum InlayHintRefreshReason {
 1617    ModifiersChanged(bool),
 1618    Toggle(bool),
 1619    SettingsChange(InlayHintSettings),
 1620    NewLinesShown,
 1621    BufferEdited(HashSet<Arc<Language>>),
 1622    RefreshRequested,
 1623    ExcerptsRemoved(Vec<ExcerptId>),
 1624}
 1625
 1626impl InlayHintRefreshReason {
 1627    fn description(&self) -> &'static str {
 1628        match self {
 1629            Self::ModifiersChanged(_) => "modifiers changed",
 1630            Self::Toggle(_) => "toggle",
 1631            Self::SettingsChange(_) => "settings change",
 1632            Self::NewLinesShown => "new lines shown",
 1633            Self::BufferEdited(_) => "buffer edited",
 1634            Self::RefreshRequested => "refresh requested",
 1635            Self::ExcerptsRemoved(_) => "excerpts removed",
 1636        }
 1637    }
 1638}
 1639
 1640pub enum FormatTarget {
 1641    Buffers(HashSet<Entity<Buffer>>),
 1642    Ranges(Vec<Range<MultiBufferPoint>>),
 1643}
 1644
 1645pub(crate) struct FocusedBlock {
 1646    id: BlockId,
 1647    focus_handle: WeakFocusHandle,
 1648}
 1649
 1650#[derive(Clone)]
 1651enum JumpData {
 1652    MultiBufferRow {
 1653        row: MultiBufferRow,
 1654        line_offset_from_top: u32,
 1655    },
 1656    MultiBufferPoint {
 1657        excerpt_id: ExcerptId,
 1658        position: Point,
 1659        anchor: text::Anchor,
 1660        line_offset_from_top: u32,
 1661    },
 1662}
 1663
 1664pub enum MultibufferSelectionMode {
 1665    First,
 1666    All,
 1667}
 1668
 1669#[derive(Clone, Copy, Debug, Default)]
 1670pub struct RewrapOptions {
 1671    pub override_language_settings: bool,
 1672    pub preserve_existing_whitespace: bool,
 1673}
 1674
 1675impl Editor {
 1676    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1677        let buffer = cx.new(|cx| Buffer::local("", cx));
 1678        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1679        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1680    }
 1681
 1682    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1683        let buffer = cx.new(|cx| Buffer::local("", cx));
 1684        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1685        Self::new(EditorMode::full(), buffer, None, window, cx)
 1686    }
 1687
 1688    pub fn auto_height(
 1689        min_lines: usize,
 1690        max_lines: usize,
 1691        window: &mut Window,
 1692        cx: &mut Context<Self>,
 1693    ) -> Self {
 1694        let buffer = cx.new(|cx| Buffer::local("", cx));
 1695        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1696        Self::new(
 1697            EditorMode::AutoHeight {
 1698                min_lines,
 1699                max_lines: Some(max_lines),
 1700            },
 1701            buffer,
 1702            None,
 1703            window,
 1704            cx,
 1705        )
 1706    }
 1707
 1708    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1709    /// The editor grows as tall as needed to fit its content.
 1710    pub fn auto_height_unbounded(
 1711        min_lines: usize,
 1712        window: &mut Window,
 1713        cx: &mut Context<Self>,
 1714    ) -> Self {
 1715        let buffer = cx.new(|cx| Buffer::local("", cx));
 1716        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1717        Self::new(
 1718            EditorMode::AutoHeight {
 1719                min_lines,
 1720                max_lines: None,
 1721            },
 1722            buffer,
 1723            None,
 1724            window,
 1725            cx,
 1726        )
 1727    }
 1728
 1729    pub fn for_buffer(
 1730        buffer: Entity<Buffer>,
 1731        project: Option<Entity<Project>>,
 1732        window: &mut Window,
 1733        cx: &mut Context<Self>,
 1734    ) -> Self {
 1735        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1736        Self::new(EditorMode::full(), buffer, project, window, cx)
 1737    }
 1738
 1739    pub fn for_multibuffer(
 1740        buffer: Entity<MultiBuffer>,
 1741        project: Option<Entity<Project>>,
 1742        window: &mut Window,
 1743        cx: &mut Context<Self>,
 1744    ) -> Self {
 1745        Self::new(EditorMode::full(), buffer, project, window, cx)
 1746    }
 1747
 1748    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1749        let mut clone = Self::new(
 1750            self.mode.clone(),
 1751            self.buffer.clone(),
 1752            self.project.clone(),
 1753            window,
 1754            cx,
 1755        );
 1756        self.display_map.update(cx, |display_map, cx| {
 1757            let snapshot = display_map.snapshot(cx);
 1758            clone.display_map.update(cx, |display_map, cx| {
 1759                display_map.set_state(&snapshot, cx);
 1760            });
 1761        });
 1762        clone.folds_did_change(cx);
 1763        clone.selections.clone_state(&self.selections);
 1764        clone.scroll_manager.clone_state(&self.scroll_manager);
 1765        clone.searchable = self.searchable;
 1766        clone.read_only = self.read_only;
 1767        clone
 1768    }
 1769
 1770    pub fn new(
 1771        mode: EditorMode,
 1772        buffer: Entity<MultiBuffer>,
 1773        project: Option<Entity<Project>>,
 1774        window: &mut Window,
 1775        cx: &mut Context<Self>,
 1776    ) -> Self {
 1777        Editor::new_internal(mode, buffer, project, None, window, cx)
 1778    }
 1779
 1780    fn new_internal(
 1781        mode: EditorMode,
 1782        buffer: Entity<MultiBuffer>,
 1783        project: Option<Entity<Project>>,
 1784        display_map: Option<Entity<DisplayMap>>,
 1785        window: &mut Window,
 1786        cx: &mut Context<Self>,
 1787    ) -> Self {
 1788        debug_assert!(
 1789            display_map.is_none() || mode.is_minimap(),
 1790            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1791        );
 1792
 1793        let full_mode = mode.is_full();
 1794        let is_minimap = mode.is_minimap();
 1795        let diagnostics_max_severity = if full_mode {
 1796            EditorSettings::get_global(cx)
 1797                .diagnostics_max_severity
 1798                .unwrap_or(DiagnosticSeverity::Hint)
 1799        } else {
 1800            DiagnosticSeverity::Off
 1801        };
 1802        let style = window.text_style();
 1803        let font_size = style.font_size.to_pixels(window.rem_size());
 1804        let editor = cx.entity().downgrade();
 1805        let fold_placeholder = FoldPlaceholder {
 1806            constrain_width: false,
 1807            render: Arc::new(move |fold_id, fold_range, cx| {
 1808                let editor = editor.clone();
 1809                div()
 1810                    .id(fold_id)
 1811                    .bg(cx.theme().colors().ghost_element_background)
 1812                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1813                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1814                    .rounded_xs()
 1815                    .size_full()
 1816                    .cursor_pointer()
 1817                    .child("")
 1818                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1819                    .on_click(move |_, _window, cx| {
 1820                        editor
 1821                            .update(cx, |editor, cx| {
 1822                                editor.unfold_ranges(
 1823                                    &[fold_range.start..fold_range.end],
 1824                                    true,
 1825                                    false,
 1826                                    cx,
 1827                                );
 1828                                cx.stop_propagation();
 1829                            })
 1830                            .ok();
 1831                    })
 1832                    .into_any()
 1833            }),
 1834            merge_adjacent: true,
 1835            ..FoldPlaceholder::default()
 1836        };
 1837        let display_map = display_map.unwrap_or_else(|| {
 1838            cx.new(|cx| {
 1839                DisplayMap::new(
 1840                    buffer.clone(),
 1841                    style.font(),
 1842                    font_size,
 1843                    None,
 1844                    FILE_HEADER_HEIGHT,
 1845                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1846                    fold_placeholder,
 1847                    diagnostics_max_severity,
 1848                    cx,
 1849                )
 1850            })
 1851        });
 1852
 1853        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1854
 1855        let blink_manager = cx.new(|cx| {
 1856            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1857            if is_minimap {
 1858                blink_manager.disable(cx);
 1859            }
 1860            blink_manager
 1861        });
 1862
 1863        let soft_wrap_mode_override =
 1864            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1865
 1866        let mut project_subscriptions = Vec::new();
 1867        if full_mode && let Some(project) = project.as_ref() {
 1868            project_subscriptions.push(cx.subscribe_in(
 1869                project,
 1870                window,
 1871                |editor, _, event, window, cx| match event {
 1872                    project::Event::RefreshCodeLens => {
 1873                        // we always query lens with actions, without storing them, always refreshing them
 1874                    }
 1875                    project::Event::RefreshInlayHints => {
 1876                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1877                    }
 1878                    project::Event::LanguageServerAdded(..)
 1879                    | project::Event::LanguageServerRemoved(..) => {
 1880                        if editor.tasks_update_task.is_none() {
 1881                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1882                        }
 1883                    }
 1884                    project::Event::SnippetEdit(id, snippet_edits) => {
 1885                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1886                            let focus_handle = editor.focus_handle(cx);
 1887                            if focus_handle.is_focused(window) {
 1888                                let snapshot = buffer.read(cx).snapshot();
 1889                                for (range, snippet) in snippet_edits {
 1890                                    let editor_range =
 1891                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1892                                    editor
 1893                                        .insert_snippet(
 1894                                            &[editor_range],
 1895                                            snippet.clone(),
 1896                                            window,
 1897                                            cx,
 1898                                        )
 1899                                        .ok();
 1900                                }
 1901                            }
 1902                        }
 1903                    }
 1904                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1905                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1906                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1907                        }
 1908                    }
 1909
 1910                    project::Event::EntryRenamed(transaction) => {
 1911                        let Some(workspace) = editor.workspace() else {
 1912                            return;
 1913                        };
 1914                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1915                        else {
 1916                            return;
 1917                        };
 1918                        if active_editor.entity_id() == cx.entity_id() {
 1919                            let edited_buffers_already_open = {
 1920                                let other_editors: Vec<Entity<Editor>> = workspace
 1921                                    .read(cx)
 1922                                    .panes()
 1923                                    .iter()
 1924                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1925                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1926                                    .collect();
 1927
 1928                                transaction.0.keys().all(|buffer| {
 1929                                    other_editors.iter().any(|editor| {
 1930                                        let multi_buffer = editor.read(cx).buffer();
 1931                                        multi_buffer.read(cx).is_singleton()
 1932                                            && multi_buffer.read(cx).as_singleton().map_or(
 1933                                                false,
 1934                                                |singleton| {
 1935                                                    singleton.entity_id() == buffer.entity_id()
 1936                                                },
 1937                                            )
 1938                                    })
 1939                                })
 1940                            };
 1941
 1942                            if !edited_buffers_already_open {
 1943                                let workspace = workspace.downgrade();
 1944                                let transaction = transaction.clone();
 1945                                cx.defer_in(window, move |_, window, cx| {
 1946                                    cx.spawn_in(window, async move |editor, cx| {
 1947                                        Self::open_project_transaction(
 1948                                            &editor,
 1949                                            workspace,
 1950                                            transaction,
 1951                                            "Rename".to_string(),
 1952                                            cx,
 1953                                        )
 1954                                        .await
 1955                                        .ok()
 1956                                    })
 1957                                    .detach();
 1958                                });
 1959                            }
 1960                        }
 1961                    }
 1962
 1963                    _ => {}
 1964                },
 1965            ));
 1966            if let Some(task_inventory) = project
 1967                .read(cx)
 1968                .task_store()
 1969                .read(cx)
 1970                .task_inventory()
 1971                .cloned()
 1972            {
 1973                project_subscriptions.push(cx.observe_in(
 1974                    &task_inventory,
 1975                    window,
 1976                    |editor, _, window, cx| {
 1977                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1978                    },
 1979                ));
 1980            };
 1981
 1982            project_subscriptions.push(cx.subscribe_in(
 1983                &project.read(cx).breakpoint_store(),
 1984                window,
 1985                |editor, _, event, window, cx| match event {
 1986                    BreakpointStoreEvent::ClearDebugLines => {
 1987                        editor.clear_row_highlights::<ActiveDebugLine>();
 1988                        editor.refresh_inline_values(cx);
 1989                    }
 1990                    BreakpointStoreEvent::SetDebugLine => {
 1991                        if editor.go_to_active_debug_line(window, cx) {
 1992                            cx.stop_propagation();
 1993                        }
 1994
 1995                        editor.refresh_inline_values(cx);
 1996                    }
 1997                    _ => {}
 1998                },
 1999            ));
 2000            let git_store = project.read(cx).git_store().clone();
 2001            let project = project.clone();
 2002            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2003                if let GitStoreEvent::RepositoryUpdated(
 2004                    _,
 2005                    RepositoryEvent::Updated {
 2006                        new_instance: true, ..
 2007                    },
 2008                    _,
 2009                ) = event
 2010                {
 2011                    this.load_diff_task = Some(
 2012                        update_uncommitted_diff_for_buffer(
 2013                            cx.entity(),
 2014                            &project,
 2015                            this.buffer.read(cx).all_buffers(),
 2016                            this.buffer.clone(),
 2017                            cx,
 2018                        )
 2019                        .shared(),
 2020                    );
 2021                }
 2022            }));
 2023        }
 2024
 2025        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2026
 2027        let inlay_hint_settings =
 2028            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2029        let focus_handle = cx.focus_handle();
 2030        if !is_minimap {
 2031            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2032                .detach();
 2033            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2034                .detach();
 2035            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2036                .detach();
 2037            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2038                .detach();
 2039            cx.observe_pending_input(window, Self::observe_pending_input)
 2040                .detach();
 2041        }
 2042
 2043        let show_indent_guides =
 2044            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2045                Some(false)
 2046            } else {
 2047                None
 2048            };
 2049
 2050        let breakpoint_store = match (&mode, project.as_ref()) {
 2051            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2052            _ => None,
 2053        };
 2054
 2055        let mut code_action_providers = Vec::new();
 2056        let mut load_uncommitted_diff = None;
 2057        if let Some(project) = project.clone() {
 2058            load_uncommitted_diff = Some(
 2059                update_uncommitted_diff_for_buffer(
 2060                    cx.entity(),
 2061                    &project,
 2062                    buffer.read(cx).all_buffers(),
 2063                    buffer.clone(),
 2064                    cx,
 2065                )
 2066                .shared(),
 2067            );
 2068            code_action_providers.push(Rc::new(project) as Rc<_>);
 2069        }
 2070
 2071        let mut editor = Self {
 2072            focus_handle,
 2073            show_cursor_when_unfocused: false,
 2074            last_focused_descendant: None,
 2075            buffer: buffer.clone(),
 2076            display_map: display_map.clone(),
 2077            placeholder_display_map: None,
 2078            selections,
 2079            scroll_manager: ScrollManager::new(cx),
 2080            columnar_selection_state: None,
 2081            add_selections_state: None,
 2082            select_next_state: None,
 2083            select_prev_state: None,
 2084            selection_history: SelectionHistory::default(),
 2085            defer_selection_effects: false,
 2086            deferred_selection_effects_state: None,
 2087            autoclose_regions: Vec::new(),
 2088            snippet_stack: InvalidationStack::default(),
 2089            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2090            ime_transaction: None,
 2091            active_diagnostics: ActiveDiagnostic::None,
 2092            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2093            inline_diagnostics_update: Task::ready(()),
 2094            inline_diagnostics: Vec::new(),
 2095            soft_wrap_mode_override,
 2096            diagnostics_max_severity,
 2097            hard_wrap: None,
 2098            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2099            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2100            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2101            project,
 2102            blink_manager: blink_manager.clone(),
 2103            show_local_selections: true,
 2104            show_scrollbars: ScrollbarAxes {
 2105                horizontal: full_mode,
 2106                vertical: full_mode,
 2107            },
 2108            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2109            offset_content: !matches!(mode, EditorMode::SingleLine),
 2110            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2111            show_gutter: full_mode,
 2112            show_line_numbers: (!full_mode).then_some(false),
 2113            use_relative_line_numbers: None,
 2114            disable_expand_excerpt_buttons: !full_mode,
 2115            show_git_diff_gutter: None,
 2116            show_code_actions: None,
 2117            show_runnables: None,
 2118            show_breakpoints: None,
 2119            show_wrap_guides: None,
 2120            show_indent_guides,
 2121            highlight_order: 0,
 2122            highlighted_rows: HashMap::default(),
 2123            background_highlights: HashMap::default(),
 2124            gutter_highlights: HashMap::default(),
 2125            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2126            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2127            nav_history: None,
 2128            context_menu: RefCell::new(None),
 2129            context_menu_options: None,
 2130            mouse_context_menu: None,
 2131            completion_tasks: Vec::new(),
 2132            inline_blame_popover: None,
 2133            inline_blame_popover_show_task: None,
 2134            signature_help_state: SignatureHelpState::default(),
 2135            auto_signature_help: None,
 2136            find_all_references_task_sources: Vec::new(),
 2137            next_completion_id: 0,
 2138            next_inlay_id: 0,
 2139            code_action_providers,
 2140            available_code_actions: None,
 2141            code_actions_task: None,
 2142            quick_selection_highlight_task: None,
 2143            debounced_selection_highlight_task: None,
 2144            document_highlights_task: None,
 2145            linked_editing_range_task: None,
 2146            pending_rename: None,
 2147            searchable: !is_minimap,
 2148            cursor_shape: EditorSettings::get_global(cx)
 2149                .cursor_shape
 2150                .unwrap_or_default(),
 2151            current_line_highlight: None,
 2152            autoindent_mode: Some(AutoindentMode::EachLine),
 2153            collapse_matches: false,
 2154            workspace: None,
 2155            input_enabled: !is_minimap,
 2156            use_modal_editing: full_mode,
 2157            read_only: is_minimap,
 2158            use_autoclose: true,
 2159            use_auto_surround: true,
 2160            auto_replace_emoji_shortcode: false,
 2161            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2162            leader_id: None,
 2163            remote_id: None,
 2164            hover_state: HoverState::default(),
 2165            pending_mouse_down: None,
 2166            hovered_link_state: None,
 2167            edit_prediction_provider: None,
 2168            active_edit_prediction: None,
 2169            stale_edit_prediction_in_menu: None,
 2170            edit_prediction_preview: EditPredictionPreview::Inactive {
 2171                released_too_fast: false,
 2172            },
 2173            inline_diagnostics_enabled: full_mode,
 2174            diagnostics_enabled: full_mode,
 2175            word_completions_enabled: full_mode,
 2176            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2177            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2178            gutter_hovered: false,
 2179            pixel_position_of_newest_cursor: None,
 2180            last_bounds: None,
 2181            last_position_map: None,
 2182            expect_bounds_change: None,
 2183            gutter_dimensions: GutterDimensions::default(),
 2184            style: None,
 2185            show_cursor_names: false,
 2186            hovered_cursors: HashMap::default(),
 2187            next_editor_action_id: EditorActionId::default(),
 2188            editor_actions: Rc::default(),
 2189            edit_predictions_hidden_for_vim_mode: false,
 2190            show_edit_predictions_override: None,
 2191            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2192            edit_prediction_settings: EditPredictionSettings::Disabled,
 2193            edit_prediction_indent_conflict: false,
 2194            edit_prediction_requires_modifier_in_indent_conflict: true,
 2195            custom_context_menu: None,
 2196            show_git_blame_gutter: false,
 2197            show_git_blame_inline: false,
 2198            show_selection_menu: None,
 2199            show_git_blame_inline_delay_task: None,
 2200            git_blame_inline_enabled: full_mode
 2201                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2202            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2203            serialize_dirty_buffers: !is_minimap
 2204                && ProjectSettings::get_global(cx)
 2205                    .session
 2206                    .restore_unsaved_buffers,
 2207            blame: None,
 2208            blame_subscription: None,
 2209            tasks: BTreeMap::default(),
 2210
 2211            breakpoint_store,
 2212            gutter_breakpoint_indicator: (None, None),
 2213            hovered_diff_hunk_row: None,
 2214            _subscriptions: (!is_minimap)
 2215                .then(|| {
 2216                    vec![
 2217                        cx.observe(&buffer, Self::on_buffer_changed),
 2218                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2219                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2220                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2221                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2222                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2223                        cx.observe_window_activation(window, |editor, window, cx| {
 2224                            let active = window.is_window_active();
 2225                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2226                                if active {
 2227                                    blink_manager.enable(cx);
 2228                                } else {
 2229                                    blink_manager.disable(cx);
 2230                                }
 2231                            });
 2232                            if active {
 2233                                editor.show_mouse_cursor(cx);
 2234                            }
 2235                        }),
 2236                    ]
 2237                })
 2238                .unwrap_or_default(),
 2239            tasks_update_task: None,
 2240            pull_diagnostics_task: Task::ready(()),
 2241            colors: None,
 2242            next_color_inlay_id: 0,
 2243            linked_edit_ranges: Default::default(),
 2244            in_project_search: false,
 2245            previous_search_ranges: None,
 2246            breadcrumb_header: None,
 2247            focused_block: None,
 2248            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2249            addons: HashMap::default(),
 2250            registered_buffers: HashMap::default(),
 2251            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2252            selection_mark_mode: false,
 2253            toggle_fold_multiple_buffers: Task::ready(()),
 2254            serialize_selections: Task::ready(()),
 2255            serialize_folds: Task::ready(()),
 2256            text_style_refinement: None,
 2257            load_diff_task: load_uncommitted_diff,
 2258            temporary_diff_override: false,
 2259            mouse_cursor_hidden: false,
 2260            minimap: None,
 2261            hide_mouse_mode: EditorSettings::get_global(cx)
 2262                .hide_mouse
 2263                .unwrap_or_default(),
 2264            change_list: ChangeList::new(),
 2265            mode,
 2266            selection_drag_state: SelectionDragState::None,
 2267            folding_newlines: Task::ready(()),
 2268            lookup_key: None,
 2269        };
 2270
 2271        if is_minimap {
 2272            return editor;
 2273        }
 2274
 2275        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2276            editor
 2277                ._subscriptions
 2278                .push(cx.observe(breakpoints, |_, _, cx| {
 2279                    cx.notify();
 2280                }));
 2281        }
 2282        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2283        editor._subscriptions.extend(project_subscriptions);
 2284
 2285        editor._subscriptions.push(cx.subscribe_in(
 2286            &cx.entity(),
 2287            window,
 2288            |editor, _, e: &EditorEvent, window, cx| match e {
 2289                EditorEvent::ScrollPositionChanged { local, .. } => {
 2290                    if *local {
 2291                        let new_anchor = editor.scroll_manager.anchor();
 2292                        let snapshot = editor.snapshot(window, cx);
 2293                        editor.update_restoration_data(cx, move |data| {
 2294                            data.scroll_position = (
 2295                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2296                                new_anchor.offset,
 2297                            );
 2298                        });
 2299                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2300                        editor.inline_blame_popover.take();
 2301                    }
 2302                }
 2303                EditorEvent::Edited { .. } => {
 2304                    if !vim_enabled(cx) {
 2305                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2306                        let pop_state = editor
 2307                            .change_list
 2308                            .last()
 2309                            .map(|previous| {
 2310                                previous.len() == selections.len()
 2311                                    && previous.iter().enumerate().all(|(ix, p)| {
 2312                                        p.to_display_point(&map).row()
 2313                                            == selections[ix].head().row()
 2314                                    })
 2315                            })
 2316                            .unwrap_or(false);
 2317                        let new_positions = selections
 2318                            .into_iter()
 2319                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2320                            .collect();
 2321                        editor
 2322                            .change_list
 2323                            .push_to_change_list(pop_state, new_positions);
 2324                    }
 2325                }
 2326                _ => (),
 2327            },
 2328        ));
 2329
 2330        if let Some(dap_store) = editor
 2331            .project
 2332            .as_ref()
 2333            .map(|project| project.read(cx).dap_store())
 2334        {
 2335            let weak_editor = cx.weak_entity();
 2336
 2337            editor
 2338                ._subscriptions
 2339                .push(
 2340                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2341                        let session_entity = cx.entity();
 2342                        weak_editor
 2343                            .update(cx, |editor, cx| {
 2344                                editor._subscriptions.push(
 2345                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2346                                );
 2347                            })
 2348                            .ok();
 2349                    }),
 2350                );
 2351
 2352            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2353                editor
 2354                    ._subscriptions
 2355                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2356            }
 2357        }
 2358
 2359        // skip adding the initial selection to selection history
 2360        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2361        editor.end_selection(window, cx);
 2362        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2363
 2364        editor.scroll_manager.show_scrollbars(window, cx);
 2365        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2366
 2367        if full_mode {
 2368            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2369            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2370
 2371            if editor.git_blame_inline_enabled {
 2372                editor.start_git_blame_inline(false, window, cx);
 2373            }
 2374
 2375            editor.go_to_active_debug_line(window, cx);
 2376
 2377            if let Some(buffer) = buffer.read(cx).as_singleton()
 2378                && let Some(project) = editor.project()
 2379            {
 2380                let handle = project.update(cx, |project, cx| {
 2381                    project.register_buffer_with_language_servers(&buffer, cx)
 2382                });
 2383                editor
 2384                    .registered_buffers
 2385                    .insert(buffer.read(cx).remote_id(), handle);
 2386            }
 2387
 2388            editor.minimap =
 2389                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2390            editor.colors = Some(LspColorData::new(cx));
 2391            editor.update_lsp_data(false, None, window, cx);
 2392        }
 2393
 2394        if editor.mode.is_full() {
 2395            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2396        }
 2397
 2398        editor
 2399    }
 2400
 2401    pub fn deploy_mouse_context_menu(
 2402        &mut self,
 2403        position: gpui::Point<Pixels>,
 2404        context_menu: Entity<ContextMenu>,
 2405        window: &mut Window,
 2406        cx: &mut Context<Self>,
 2407    ) {
 2408        self.mouse_context_menu = Some(MouseContextMenu::new(
 2409            self,
 2410            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2411            context_menu,
 2412            window,
 2413            cx,
 2414        ));
 2415    }
 2416
 2417    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2418        self.mouse_context_menu
 2419            .as_ref()
 2420            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2421    }
 2422
 2423    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2424        if self
 2425            .selections
 2426            .pending_anchor()
 2427            .is_some_and(|pending_selection| {
 2428                let snapshot = self.buffer().read(cx).snapshot(cx);
 2429                pending_selection.range().includes(range, &snapshot)
 2430            })
 2431        {
 2432            return true;
 2433        }
 2434
 2435        self.selections
 2436            .disjoint_in_range::<usize>(range.clone(), cx)
 2437            .into_iter()
 2438            .any(|selection| {
 2439                // This is needed to cover a corner case, if we just check for an existing
 2440                // selection in the fold range, having a cursor at the start of the fold
 2441                // marks it as selected. Non-empty selections don't cause this.
 2442                let length = selection.end - selection.start;
 2443                length > 0
 2444            })
 2445    }
 2446
 2447    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2448        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2449    }
 2450
 2451    fn key_context_internal(
 2452        &self,
 2453        has_active_edit_prediction: bool,
 2454        window: &Window,
 2455        cx: &App,
 2456    ) -> KeyContext {
 2457        let mut key_context = KeyContext::new_with_defaults();
 2458        key_context.add("Editor");
 2459        let mode = match self.mode {
 2460            EditorMode::SingleLine => "single_line",
 2461            EditorMode::AutoHeight { .. } => "auto_height",
 2462            EditorMode::Minimap { .. } => "minimap",
 2463            EditorMode::Full { .. } => "full",
 2464        };
 2465
 2466        if EditorSettings::jupyter_enabled(cx) {
 2467            key_context.add("jupyter");
 2468        }
 2469
 2470        key_context.set("mode", mode);
 2471        if self.pending_rename.is_some() {
 2472            key_context.add("renaming");
 2473        }
 2474
 2475        match self.context_menu.borrow().as_ref() {
 2476            Some(CodeContextMenu::Completions(menu)) => {
 2477                if menu.visible() {
 2478                    key_context.add("menu");
 2479                    key_context.add("showing_completions");
 2480                }
 2481            }
 2482            Some(CodeContextMenu::CodeActions(menu)) => {
 2483                if menu.visible() {
 2484                    key_context.add("menu");
 2485                    key_context.add("showing_code_actions")
 2486                }
 2487            }
 2488            None => {}
 2489        }
 2490
 2491        if self.signature_help_state.has_multiple_signatures() {
 2492            key_context.add("showing_signature_help");
 2493        }
 2494
 2495        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2496        if !self.focus_handle(cx).contains_focused(window, cx)
 2497            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2498        {
 2499            for addon in self.addons.values() {
 2500                addon.extend_key_context(&mut key_context, cx)
 2501            }
 2502        }
 2503
 2504        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2505            if let Some(extension) = singleton_buffer
 2506                .read(cx)
 2507                .file()
 2508                .and_then(|file| file.path().extension())
 2509            {
 2510                key_context.set("extension", extension.to_string());
 2511            }
 2512        } else {
 2513            key_context.add("multibuffer");
 2514        }
 2515
 2516        if has_active_edit_prediction {
 2517            if self.edit_prediction_in_conflict() {
 2518                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2519            } else {
 2520                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2521                key_context.add("copilot_suggestion");
 2522            }
 2523        }
 2524
 2525        if self.selection_mark_mode {
 2526            key_context.add("selection_mode");
 2527        }
 2528
 2529        key_context
 2530    }
 2531
 2532    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2533        self.last_bounds.as_ref()
 2534    }
 2535
 2536    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2537        if self.mouse_cursor_hidden {
 2538            self.mouse_cursor_hidden = false;
 2539            cx.notify();
 2540        }
 2541    }
 2542
 2543    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2544        let hide_mouse_cursor = match origin {
 2545            HideMouseCursorOrigin::TypingAction => {
 2546                matches!(
 2547                    self.hide_mouse_mode,
 2548                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2549                )
 2550            }
 2551            HideMouseCursorOrigin::MovementAction => {
 2552                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2553            }
 2554        };
 2555        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2556            self.mouse_cursor_hidden = hide_mouse_cursor;
 2557            cx.notify();
 2558        }
 2559    }
 2560
 2561    pub fn edit_prediction_in_conflict(&self) -> bool {
 2562        if !self.show_edit_predictions_in_menu() {
 2563            return false;
 2564        }
 2565
 2566        let showing_completions = self
 2567            .context_menu
 2568            .borrow()
 2569            .as_ref()
 2570            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2571
 2572        showing_completions
 2573            || self.edit_prediction_requires_modifier()
 2574            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2575            // bindings to insert tab characters.
 2576            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2577    }
 2578
 2579    pub fn accept_edit_prediction_keybind(
 2580        &self,
 2581        accept_partial: bool,
 2582        window: &Window,
 2583        cx: &App,
 2584    ) -> AcceptEditPredictionBinding {
 2585        let key_context = self.key_context_internal(true, window, cx);
 2586        let in_conflict = self.edit_prediction_in_conflict();
 2587
 2588        let bindings = if accept_partial {
 2589            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2590        } else {
 2591            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2592        };
 2593
 2594        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2595        // just the first one.
 2596        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2597            !in_conflict
 2598                || binding
 2599                    .keystrokes()
 2600                    .first()
 2601                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2602        }))
 2603    }
 2604
 2605    pub fn new_file(
 2606        workspace: &mut Workspace,
 2607        _: &workspace::NewFile,
 2608        window: &mut Window,
 2609        cx: &mut Context<Workspace>,
 2610    ) {
 2611        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2612            "Failed to create buffer",
 2613            window,
 2614            cx,
 2615            |e, _, _| match e.error_code() {
 2616                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2617                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2618                e.error_tag("required").unwrap_or("the latest version")
 2619            )),
 2620                _ => None,
 2621            },
 2622        );
 2623    }
 2624
 2625    pub fn new_in_workspace(
 2626        workspace: &mut Workspace,
 2627        window: &mut Window,
 2628        cx: &mut Context<Workspace>,
 2629    ) -> Task<Result<Entity<Editor>>> {
 2630        let project = workspace.project().clone();
 2631        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2632
 2633        cx.spawn_in(window, async move |workspace, cx| {
 2634            let buffer = create.await?;
 2635            workspace.update_in(cx, |workspace, window, cx| {
 2636                let editor =
 2637                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2638                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2639                editor
 2640            })
 2641        })
 2642    }
 2643
 2644    fn new_file_vertical(
 2645        workspace: &mut Workspace,
 2646        _: &workspace::NewFileSplitVertical,
 2647        window: &mut Window,
 2648        cx: &mut Context<Workspace>,
 2649    ) {
 2650        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2651    }
 2652
 2653    fn new_file_horizontal(
 2654        workspace: &mut Workspace,
 2655        _: &workspace::NewFileSplitHorizontal,
 2656        window: &mut Window,
 2657        cx: &mut Context<Workspace>,
 2658    ) {
 2659        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2660    }
 2661
 2662    fn new_file_in_direction(
 2663        workspace: &mut Workspace,
 2664        direction: SplitDirection,
 2665        window: &mut Window,
 2666        cx: &mut Context<Workspace>,
 2667    ) {
 2668        let project = workspace.project().clone();
 2669        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2670
 2671        cx.spawn_in(window, async move |workspace, cx| {
 2672            let buffer = create.await?;
 2673            workspace.update_in(cx, move |workspace, window, cx| {
 2674                workspace.split_item(
 2675                    direction,
 2676                    Box::new(
 2677                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2678                    ),
 2679                    window,
 2680                    cx,
 2681                )
 2682            })?;
 2683            anyhow::Ok(())
 2684        })
 2685        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2686            match e.error_code() {
 2687                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2688                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2689                e.error_tag("required").unwrap_or("the latest version")
 2690            )),
 2691                _ => None,
 2692            }
 2693        });
 2694    }
 2695
 2696    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2697        self.leader_id
 2698    }
 2699
 2700    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2701        &self.buffer
 2702    }
 2703
 2704    pub fn project(&self) -> Option<&Entity<Project>> {
 2705        self.project.as_ref()
 2706    }
 2707
 2708    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2709        self.workspace.as_ref()?.0.upgrade()
 2710    }
 2711
 2712    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2713        self.buffer().read(cx).title(cx)
 2714    }
 2715
 2716    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2717        let git_blame_gutter_max_author_length = self
 2718            .render_git_blame_gutter(cx)
 2719            .then(|| {
 2720                if let Some(blame) = self.blame.as_ref() {
 2721                    let max_author_length =
 2722                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2723                    Some(max_author_length)
 2724                } else {
 2725                    None
 2726                }
 2727            })
 2728            .flatten();
 2729
 2730        EditorSnapshot {
 2731            mode: self.mode.clone(),
 2732            show_gutter: self.show_gutter,
 2733            show_line_numbers: self.show_line_numbers,
 2734            show_git_diff_gutter: self.show_git_diff_gutter,
 2735            show_code_actions: self.show_code_actions,
 2736            show_runnables: self.show_runnables,
 2737            show_breakpoints: self.show_breakpoints,
 2738            git_blame_gutter_max_author_length,
 2739            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2740            placeholder_display_snapshot: self
 2741                .placeholder_display_map
 2742                .as_ref()
 2743                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2744            scroll_anchor: self.scroll_manager.anchor(),
 2745            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2746            is_focused: self.focus_handle.is_focused(window),
 2747            current_line_highlight: self
 2748                .current_line_highlight
 2749                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2750            gutter_hovered: self.gutter_hovered,
 2751        }
 2752    }
 2753
 2754    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2755        self.buffer.read(cx).language_at(point, cx)
 2756    }
 2757
 2758    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2759        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2760    }
 2761
 2762    pub fn active_excerpt(
 2763        &self,
 2764        cx: &App,
 2765    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2766        self.buffer
 2767            .read(cx)
 2768            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2769    }
 2770
 2771    pub fn mode(&self) -> &EditorMode {
 2772        &self.mode
 2773    }
 2774
 2775    pub fn set_mode(&mut self, mode: EditorMode) {
 2776        self.mode = mode;
 2777    }
 2778
 2779    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2780        self.collaboration_hub.as_deref()
 2781    }
 2782
 2783    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2784        self.collaboration_hub = Some(hub);
 2785    }
 2786
 2787    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2788        self.in_project_search = in_project_search;
 2789    }
 2790
 2791    pub fn set_custom_context_menu(
 2792        &mut self,
 2793        f: impl 'static
 2794        + Fn(
 2795            &mut Self,
 2796            DisplayPoint,
 2797            &mut Window,
 2798            &mut Context<Self>,
 2799        ) -> Option<Entity<ui::ContextMenu>>,
 2800    ) {
 2801        self.custom_context_menu = Some(Box::new(f))
 2802    }
 2803
 2804    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2805        self.completion_provider = provider;
 2806    }
 2807
 2808    #[cfg(any(test, feature = "test-support"))]
 2809    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2810        self.completion_provider.clone()
 2811    }
 2812
 2813    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2814        self.semantics_provider.clone()
 2815    }
 2816
 2817    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2818        self.semantics_provider = provider;
 2819    }
 2820
 2821    pub fn set_edit_prediction_provider<T>(
 2822        &mut self,
 2823        provider: Option<Entity<T>>,
 2824        window: &mut Window,
 2825        cx: &mut Context<Self>,
 2826    ) where
 2827        T: EditPredictionProvider,
 2828    {
 2829        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2830            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2831                if this.focus_handle.is_focused(window) {
 2832                    this.update_visible_edit_prediction(window, cx);
 2833                }
 2834            }),
 2835            provider: Arc::new(provider),
 2836        });
 2837        self.update_edit_prediction_settings(cx);
 2838        self.refresh_edit_prediction(false, false, window, cx);
 2839    }
 2840
 2841    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2842        self.placeholder_display_map
 2843            .as_ref()
 2844            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2845    }
 2846
 2847    pub fn set_placeholder_text(
 2848        &mut self,
 2849        placeholder_text: &str,
 2850        window: &mut Window,
 2851        cx: &mut Context<Self>,
 2852    ) {
 2853        let multibuffer = cx
 2854            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2855
 2856        let style = window.text_style();
 2857
 2858        self.placeholder_display_map = Some(cx.new(|cx| {
 2859            DisplayMap::new(
 2860                multibuffer,
 2861                style.font(),
 2862                style.font_size.to_pixels(window.rem_size()),
 2863                None,
 2864                FILE_HEADER_HEIGHT,
 2865                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2866                Default::default(),
 2867                DiagnosticSeverity::Off,
 2868                cx,
 2869            )
 2870        }));
 2871        cx.notify();
 2872    }
 2873
 2874    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2875        self.cursor_shape = cursor_shape;
 2876
 2877        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2878        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2879
 2880        cx.notify();
 2881    }
 2882
 2883    pub fn set_current_line_highlight(
 2884        &mut self,
 2885        current_line_highlight: Option<CurrentLineHighlight>,
 2886    ) {
 2887        self.current_line_highlight = current_line_highlight;
 2888    }
 2889
 2890    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2891        self.collapse_matches = collapse_matches;
 2892    }
 2893
 2894    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2895        let buffers = self.buffer.read(cx).all_buffers();
 2896        let Some(project) = self.project.as_ref() else {
 2897            return;
 2898        };
 2899        project.update(cx, |project, cx| {
 2900            for buffer in buffers {
 2901                self.registered_buffers
 2902                    .entry(buffer.read(cx).remote_id())
 2903                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2904            }
 2905        })
 2906    }
 2907
 2908    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2909        if self.collapse_matches {
 2910            return range.start..range.start;
 2911        }
 2912        range.clone()
 2913    }
 2914
 2915    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2916        if self.display_map.read(cx).clip_at_line_ends != clip {
 2917            self.display_map
 2918                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2919        }
 2920    }
 2921
 2922    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2923        self.input_enabled = input_enabled;
 2924    }
 2925
 2926    pub fn set_edit_predictions_hidden_for_vim_mode(
 2927        &mut self,
 2928        hidden: bool,
 2929        window: &mut Window,
 2930        cx: &mut Context<Self>,
 2931    ) {
 2932        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2933            self.edit_predictions_hidden_for_vim_mode = hidden;
 2934            if hidden {
 2935                self.update_visible_edit_prediction(window, cx);
 2936            } else {
 2937                self.refresh_edit_prediction(true, false, window, cx);
 2938            }
 2939        }
 2940    }
 2941
 2942    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2943        self.menu_edit_predictions_policy = value;
 2944    }
 2945
 2946    pub fn set_autoindent(&mut self, autoindent: bool) {
 2947        if autoindent {
 2948            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2949        } else {
 2950            self.autoindent_mode = None;
 2951        }
 2952    }
 2953
 2954    pub fn read_only(&self, cx: &App) -> bool {
 2955        self.read_only || self.buffer.read(cx).read_only()
 2956    }
 2957
 2958    pub fn set_read_only(&mut self, read_only: bool) {
 2959        self.read_only = read_only;
 2960    }
 2961
 2962    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2963        self.use_autoclose = autoclose;
 2964    }
 2965
 2966    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2967        self.use_auto_surround = auto_surround;
 2968    }
 2969
 2970    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2971        self.auto_replace_emoji_shortcode = auto_replace;
 2972    }
 2973
 2974    pub fn toggle_edit_predictions(
 2975        &mut self,
 2976        _: &ToggleEditPrediction,
 2977        window: &mut Window,
 2978        cx: &mut Context<Self>,
 2979    ) {
 2980        if self.show_edit_predictions_override.is_some() {
 2981            self.set_show_edit_predictions(None, window, cx);
 2982        } else {
 2983            let show_edit_predictions = !self.edit_predictions_enabled();
 2984            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2985        }
 2986    }
 2987
 2988    pub fn set_show_edit_predictions(
 2989        &mut self,
 2990        show_edit_predictions: Option<bool>,
 2991        window: &mut Window,
 2992        cx: &mut Context<Self>,
 2993    ) {
 2994        self.show_edit_predictions_override = show_edit_predictions;
 2995        self.update_edit_prediction_settings(cx);
 2996
 2997        if let Some(false) = show_edit_predictions {
 2998            self.discard_edit_prediction(false, cx);
 2999        } else {
 3000            self.refresh_edit_prediction(false, true, window, cx);
 3001        }
 3002    }
 3003
 3004    fn edit_predictions_disabled_in_scope(
 3005        &self,
 3006        buffer: &Entity<Buffer>,
 3007        buffer_position: language::Anchor,
 3008        cx: &App,
 3009    ) -> bool {
 3010        let snapshot = buffer.read(cx).snapshot();
 3011        let settings = snapshot.settings_at(buffer_position, cx);
 3012
 3013        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3014            return false;
 3015        };
 3016
 3017        scope.override_name().is_some_and(|scope_name| {
 3018            settings
 3019                .edit_predictions_disabled_in
 3020                .iter()
 3021                .any(|s| s == scope_name)
 3022        })
 3023    }
 3024
 3025    pub fn set_use_modal_editing(&mut self, to: bool) {
 3026        self.use_modal_editing = to;
 3027    }
 3028
 3029    pub fn use_modal_editing(&self) -> bool {
 3030        self.use_modal_editing
 3031    }
 3032
 3033    fn selections_did_change(
 3034        &mut self,
 3035        local: bool,
 3036        old_cursor_position: &Anchor,
 3037        effects: SelectionEffects,
 3038        window: &mut Window,
 3039        cx: &mut Context<Self>,
 3040    ) {
 3041        window.invalidate_character_coordinates();
 3042
 3043        // Copy selections to primary selection buffer
 3044        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3045        if local {
 3046            let selections = self.selections.all::<usize>(cx);
 3047            let buffer_handle = self.buffer.read(cx).read(cx);
 3048
 3049            let mut text = String::new();
 3050            for (index, selection) in selections.iter().enumerate() {
 3051                let text_for_selection = buffer_handle
 3052                    .text_for_range(selection.start..selection.end)
 3053                    .collect::<String>();
 3054
 3055                text.push_str(&text_for_selection);
 3056                if index != selections.len() - 1 {
 3057                    text.push('\n');
 3058                }
 3059            }
 3060
 3061            if !text.is_empty() {
 3062                cx.write_to_primary(ClipboardItem::new_string(text));
 3063            }
 3064        }
 3065
 3066        let selection_anchors = self.selections.disjoint_anchors_arc();
 3067
 3068        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3069            self.buffer.update(cx, |buffer, cx| {
 3070                buffer.set_active_selections(
 3071                    &selection_anchors,
 3072                    self.selections.line_mode(),
 3073                    self.cursor_shape,
 3074                    cx,
 3075                )
 3076            });
 3077        }
 3078        let display_map = self
 3079            .display_map
 3080            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3081        let buffer = &display_map.buffer_snapshot;
 3082        if self.selections.count() == 1 {
 3083            self.add_selections_state = None;
 3084        }
 3085        self.select_next_state = None;
 3086        self.select_prev_state = None;
 3087        self.select_syntax_node_history.try_clear();
 3088        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3089        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3090        self.take_rename(false, window, cx);
 3091
 3092        let newest_selection = self.selections.newest_anchor();
 3093        let new_cursor_position = newest_selection.head();
 3094        let selection_start = newest_selection.start;
 3095
 3096        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3097            self.push_to_nav_history(
 3098                *old_cursor_position,
 3099                Some(new_cursor_position.to_point(buffer)),
 3100                false,
 3101                effects.nav_history == Some(true),
 3102                cx,
 3103            );
 3104        }
 3105
 3106        if local {
 3107            if let Some(buffer_id) = new_cursor_position.buffer_id
 3108                && !self.registered_buffers.contains_key(&buffer_id)
 3109                && let Some(project) = self.project.as_ref()
 3110            {
 3111                project.update(cx, |project, cx| {
 3112                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3113                        return;
 3114                    };
 3115                    self.registered_buffers.insert(
 3116                        buffer_id,
 3117                        project.register_buffer_with_language_servers(&buffer, cx),
 3118                    );
 3119                })
 3120            }
 3121
 3122            let mut context_menu = self.context_menu.borrow_mut();
 3123            let completion_menu = match context_menu.as_ref() {
 3124                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3125                Some(CodeContextMenu::CodeActions(_)) => {
 3126                    *context_menu = None;
 3127                    None
 3128                }
 3129                None => None,
 3130            };
 3131            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3132            drop(context_menu);
 3133
 3134            if effects.completions
 3135                && let Some(completion_position) = completion_position
 3136            {
 3137                let start_offset = selection_start.to_offset(buffer);
 3138                let position_matches = start_offset == completion_position.to_offset(buffer);
 3139                let continue_showing = if position_matches {
 3140                    if self.snippet_stack.is_empty() {
 3141                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3142                            == Some(CharKind::Word)
 3143                    } else {
 3144                        // Snippet choices can be shown even when the cursor is in whitespace.
 3145                        // Dismissing the menu with actions like backspace is handled by
 3146                        // invalidation regions.
 3147                        true
 3148                    }
 3149                } else {
 3150                    false
 3151                };
 3152
 3153                if continue_showing {
 3154                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3155                } else {
 3156                    self.hide_context_menu(window, cx);
 3157                }
 3158            }
 3159
 3160            hide_hover(self, cx);
 3161
 3162            if old_cursor_position.to_display_point(&display_map).row()
 3163                != new_cursor_position.to_display_point(&display_map).row()
 3164            {
 3165                self.available_code_actions.take();
 3166            }
 3167            self.refresh_code_actions(window, cx);
 3168            self.refresh_document_highlights(cx);
 3169            self.refresh_selected_text_highlights(false, window, cx);
 3170            refresh_matching_bracket_highlights(self, window, cx);
 3171            self.update_visible_edit_prediction(window, cx);
 3172            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3173            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 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(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3222                                .log_err();
 3223                        });
 3224            }
 3225        }
 3226
 3227        cx.notify();
 3228    }
 3229
 3230    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3231        use text::ToOffset as _;
 3232        use text::ToPoint as _;
 3233
 3234        if self.mode.is_minimap()
 3235            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3236        {
 3237            return;
 3238        }
 3239
 3240        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3241            return;
 3242        };
 3243
 3244        let snapshot = singleton.read(cx).snapshot();
 3245        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3246            let display_snapshot = display_map.snapshot(cx);
 3247
 3248            display_snapshot
 3249                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3250                .map(|fold| {
 3251                    fold.range.start.text_anchor.to_point(&snapshot)
 3252                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3253                })
 3254                .collect()
 3255        });
 3256        self.update_restoration_data(cx, |data| {
 3257            data.folds = inmemory_folds;
 3258        });
 3259
 3260        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3261            return;
 3262        };
 3263        let background_executor = cx.background_executor().clone();
 3264        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3265        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3266            display_map
 3267                .snapshot(cx)
 3268                .folds_in_range(0..snapshot.len())
 3269                .map(|fold| {
 3270                    (
 3271                        fold.range.start.text_anchor.to_offset(&snapshot),
 3272                        fold.range.end.text_anchor.to_offset(&snapshot),
 3273                    )
 3274                })
 3275                .collect()
 3276        });
 3277        self.serialize_folds = cx.background_spawn(async move {
 3278            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3279            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3280                .await
 3281                .with_context(|| {
 3282                    format!(
 3283                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3284                    )
 3285                })
 3286                .log_err();
 3287        });
 3288    }
 3289
 3290    pub fn sync_selections(
 3291        &mut self,
 3292        other: Entity<Editor>,
 3293        cx: &mut Context<Self>,
 3294    ) -> gpui::Subscription {
 3295        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3296        self.selections.change_with(cx, |selections| {
 3297            selections.select_anchors(other_selections);
 3298        });
 3299
 3300        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3301            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3302                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3303                if other_selections.is_empty() {
 3304                    return;
 3305                }
 3306                this.selections.change_with(cx, |selections| {
 3307                    selections.select_anchors(other_selections);
 3308                });
 3309            }
 3310        });
 3311
 3312        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3313            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3314                let these_selections = this.selections.disjoint_anchors().to_vec();
 3315                if these_selections.is_empty() {
 3316                    return;
 3317                }
 3318                other.update(cx, |other_editor, cx| {
 3319                    other_editor.selections.change_with(cx, |selections| {
 3320                        selections.select_anchors(these_selections);
 3321                    })
 3322                });
 3323            }
 3324        });
 3325
 3326        Subscription::join(other_subscription, this_subscription)
 3327    }
 3328
 3329    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3330    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3331    /// effects of selection change occur at the end of the transaction.
 3332    pub fn change_selections<R>(
 3333        &mut self,
 3334        effects: SelectionEffects,
 3335        window: &mut Window,
 3336        cx: &mut Context<Self>,
 3337        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3338    ) -> R {
 3339        if let Some(state) = &mut self.deferred_selection_effects_state {
 3340            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3341            state.effects.completions = effects.completions;
 3342            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3343            let (changed, result) = self.selections.change_with(cx, change);
 3344            state.changed |= changed;
 3345            return result;
 3346        }
 3347        let mut state = DeferredSelectionEffectsState {
 3348            changed: false,
 3349            effects,
 3350            old_cursor_position: self.selections.newest_anchor().head(),
 3351            history_entry: SelectionHistoryEntry {
 3352                selections: self.selections.disjoint_anchors_arc(),
 3353                select_next_state: self.select_next_state.clone(),
 3354                select_prev_state: self.select_prev_state.clone(),
 3355                add_selections_state: self.add_selections_state.clone(),
 3356            },
 3357        };
 3358        let (changed, result) = self.selections.change_with(cx, change);
 3359        state.changed = state.changed || changed;
 3360        if self.defer_selection_effects {
 3361            self.deferred_selection_effects_state = Some(state);
 3362        } else {
 3363            self.apply_selection_effects(state, window, cx);
 3364        }
 3365        result
 3366    }
 3367
 3368    /// Defers the effects of selection change, so that the effects of multiple calls to
 3369    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3370    /// to selection history and the state of popovers based on selection position aren't
 3371    /// erroneously updated.
 3372    pub fn with_selection_effects_deferred<R>(
 3373        &mut self,
 3374        window: &mut Window,
 3375        cx: &mut Context<Self>,
 3376        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3377    ) -> R {
 3378        let already_deferred = self.defer_selection_effects;
 3379        self.defer_selection_effects = true;
 3380        let result = update(self, window, cx);
 3381        if !already_deferred {
 3382            self.defer_selection_effects = false;
 3383            if let Some(state) = self.deferred_selection_effects_state.take() {
 3384                self.apply_selection_effects(state, window, cx);
 3385            }
 3386        }
 3387        result
 3388    }
 3389
 3390    fn apply_selection_effects(
 3391        &mut self,
 3392        state: DeferredSelectionEffectsState,
 3393        window: &mut Window,
 3394        cx: &mut Context<Self>,
 3395    ) {
 3396        if state.changed {
 3397            self.selection_history.push(state.history_entry);
 3398
 3399            if let Some(autoscroll) = state.effects.scroll {
 3400                self.request_autoscroll(autoscroll, cx);
 3401            }
 3402
 3403            let old_cursor_position = &state.old_cursor_position;
 3404
 3405            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3406
 3407            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3408                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3409            }
 3410        }
 3411    }
 3412
 3413    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3414    where
 3415        I: IntoIterator<Item = (Range<S>, T)>,
 3416        S: ToOffset,
 3417        T: Into<Arc<str>>,
 3418    {
 3419        if self.read_only(cx) {
 3420            return;
 3421        }
 3422
 3423        self.buffer
 3424            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3425    }
 3426
 3427    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3428    where
 3429        I: IntoIterator<Item = (Range<S>, T)>,
 3430        S: ToOffset,
 3431        T: Into<Arc<str>>,
 3432    {
 3433        if self.read_only(cx) {
 3434            return;
 3435        }
 3436
 3437        self.buffer.update(cx, |buffer, cx| {
 3438            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3439        });
 3440    }
 3441
 3442    pub fn edit_with_block_indent<I, S, T>(
 3443        &mut self,
 3444        edits: I,
 3445        original_indent_columns: Vec<Option<u32>>,
 3446        cx: &mut Context<Self>,
 3447    ) where
 3448        I: IntoIterator<Item = (Range<S>, T)>,
 3449        S: ToOffset,
 3450        T: Into<Arc<str>>,
 3451    {
 3452        if self.read_only(cx) {
 3453            return;
 3454        }
 3455
 3456        self.buffer.update(cx, |buffer, cx| {
 3457            buffer.edit(
 3458                edits,
 3459                Some(AutoindentMode::Block {
 3460                    original_indent_columns,
 3461                }),
 3462                cx,
 3463            )
 3464        });
 3465    }
 3466
 3467    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3468        self.hide_context_menu(window, cx);
 3469
 3470        match phase {
 3471            SelectPhase::Begin {
 3472                position,
 3473                add,
 3474                click_count,
 3475            } => self.begin_selection(position, add, click_count, window, cx),
 3476            SelectPhase::BeginColumnar {
 3477                position,
 3478                goal_column,
 3479                reset,
 3480                mode,
 3481            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3482            SelectPhase::Extend {
 3483                position,
 3484                click_count,
 3485            } => self.extend_selection(position, click_count, window, cx),
 3486            SelectPhase::Update {
 3487                position,
 3488                goal_column,
 3489                scroll_delta,
 3490            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3491            SelectPhase::End => self.end_selection(window, cx),
 3492        }
 3493    }
 3494
 3495    fn extend_selection(
 3496        &mut self,
 3497        position: DisplayPoint,
 3498        click_count: usize,
 3499        window: &mut Window,
 3500        cx: &mut Context<Self>,
 3501    ) {
 3502        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3503        let tail = self.selections.newest::<usize>(cx).tail();
 3504        self.begin_selection(position, false, click_count, window, cx);
 3505
 3506        let position = position.to_offset(&display_map, Bias::Left);
 3507        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3508
 3509        let mut pending_selection = self
 3510            .selections
 3511            .pending_anchor()
 3512            .cloned()
 3513            .expect("extend_selection not called with pending selection");
 3514        if position >= tail {
 3515            pending_selection.start = tail_anchor;
 3516        } else {
 3517            pending_selection.end = tail_anchor;
 3518            pending_selection.reversed = true;
 3519        }
 3520
 3521        let mut pending_mode = self.selections.pending_mode().unwrap();
 3522        match &mut pending_mode {
 3523            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3524            _ => {}
 3525        }
 3526
 3527        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3528            SelectionEffects::scroll(Autoscroll::fit())
 3529        } else {
 3530            SelectionEffects::no_scroll()
 3531        };
 3532
 3533        self.change_selections(effects, window, cx, |s| {
 3534            s.set_pending(pending_selection.clone(), pending_mode)
 3535        });
 3536    }
 3537
 3538    fn begin_selection(
 3539        &mut self,
 3540        position: DisplayPoint,
 3541        add: bool,
 3542        click_count: usize,
 3543        window: &mut Window,
 3544        cx: &mut Context<Self>,
 3545    ) {
 3546        if !self.focus_handle.is_focused(window) {
 3547            self.last_focused_descendant = None;
 3548            window.focus(&self.focus_handle);
 3549        }
 3550
 3551        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3552        let buffer = &display_map.buffer_snapshot;
 3553        let position = display_map.clip_point(position, Bias::Left);
 3554
 3555        let start;
 3556        let end;
 3557        let mode;
 3558        let mut auto_scroll;
 3559        match click_count {
 3560            1 => {
 3561                start = buffer.anchor_before(position.to_point(&display_map));
 3562                end = start;
 3563                mode = SelectMode::Character;
 3564                auto_scroll = true;
 3565            }
 3566            2 => {
 3567                let position = display_map
 3568                    .clip_point(position, Bias::Left)
 3569                    .to_offset(&display_map, Bias::Left);
 3570                let (range, _) = buffer.surrounding_word(position, None);
 3571                start = buffer.anchor_before(range.start);
 3572                end = buffer.anchor_before(range.end);
 3573                mode = SelectMode::Word(start..end);
 3574                auto_scroll = true;
 3575            }
 3576            3 => {
 3577                let position = display_map
 3578                    .clip_point(position, Bias::Left)
 3579                    .to_point(&display_map);
 3580                let line_start = display_map.prev_line_boundary(position).0;
 3581                let next_line_start = buffer.clip_point(
 3582                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3583                    Bias::Left,
 3584                );
 3585                start = buffer.anchor_before(line_start);
 3586                end = buffer.anchor_before(next_line_start);
 3587                mode = SelectMode::Line(start..end);
 3588                auto_scroll = true;
 3589            }
 3590            _ => {
 3591                start = buffer.anchor_before(0);
 3592                end = buffer.anchor_before(buffer.len());
 3593                mode = SelectMode::All;
 3594                auto_scroll = false;
 3595            }
 3596        }
 3597        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3598
 3599        let point_to_delete: Option<usize> = {
 3600            let selected_points: Vec<Selection<Point>> =
 3601                self.selections.disjoint_in_range(start..end, cx);
 3602
 3603            if !add || click_count > 1 {
 3604                None
 3605            } else if !selected_points.is_empty() {
 3606                Some(selected_points[0].id)
 3607            } else {
 3608                let clicked_point_already_selected =
 3609                    self.selections.disjoint_anchors().iter().find(|selection| {
 3610                        selection.start.to_point(buffer) == start.to_point(buffer)
 3611                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3612                    });
 3613
 3614                clicked_point_already_selected.map(|selection| selection.id)
 3615            }
 3616        };
 3617
 3618        let selections_count = self.selections.count();
 3619        let effects = if auto_scroll {
 3620            SelectionEffects::default()
 3621        } else {
 3622            SelectionEffects::no_scroll()
 3623        };
 3624
 3625        self.change_selections(effects, window, cx, |s| {
 3626            if let Some(point_to_delete) = point_to_delete {
 3627                s.delete(point_to_delete);
 3628
 3629                if selections_count == 1 {
 3630                    s.set_pending_anchor_range(start..end, mode);
 3631                }
 3632            } else {
 3633                if !add {
 3634                    s.clear_disjoint();
 3635                }
 3636
 3637                s.set_pending_anchor_range(start..end, mode);
 3638            }
 3639        });
 3640    }
 3641
 3642    fn begin_columnar_selection(
 3643        &mut self,
 3644        position: DisplayPoint,
 3645        goal_column: u32,
 3646        reset: bool,
 3647        mode: ColumnarMode,
 3648        window: &mut Window,
 3649        cx: &mut Context<Self>,
 3650    ) {
 3651        if !self.focus_handle.is_focused(window) {
 3652            self.last_focused_descendant = None;
 3653            window.focus(&self.focus_handle);
 3654        }
 3655
 3656        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3657
 3658        if reset {
 3659            let pointer_position = display_map
 3660                .buffer_snapshot
 3661                .anchor_before(position.to_point(&display_map));
 3662
 3663            self.change_selections(
 3664                SelectionEffects::scroll(Autoscroll::newest()),
 3665                window,
 3666                cx,
 3667                |s| {
 3668                    s.clear_disjoint();
 3669                    s.set_pending_anchor_range(
 3670                        pointer_position..pointer_position,
 3671                        SelectMode::Character,
 3672                    );
 3673                },
 3674            );
 3675        };
 3676
 3677        let tail = self.selections.newest::<Point>(cx).tail();
 3678        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3679        self.columnar_selection_state = match mode {
 3680            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3681                selection_tail: selection_anchor,
 3682                display_point: if reset {
 3683                    if position.column() != goal_column {
 3684                        Some(DisplayPoint::new(position.row(), goal_column))
 3685                    } else {
 3686                        None
 3687                    }
 3688                } else {
 3689                    None
 3690                },
 3691            }),
 3692            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3693                selection_tail: selection_anchor,
 3694            }),
 3695        };
 3696
 3697        if !reset {
 3698            self.select_columns(position, goal_column, &display_map, window, cx);
 3699        }
 3700    }
 3701
 3702    fn update_selection(
 3703        &mut self,
 3704        position: DisplayPoint,
 3705        goal_column: u32,
 3706        scroll_delta: gpui::Point<f32>,
 3707        window: &mut Window,
 3708        cx: &mut Context<Self>,
 3709    ) {
 3710        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3711
 3712        if self.columnar_selection_state.is_some() {
 3713            self.select_columns(position, goal_column, &display_map, window, cx);
 3714        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3715            let buffer = &display_map.buffer_snapshot;
 3716            let head;
 3717            let tail;
 3718            let mode = self.selections.pending_mode().unwrap();
 3719            match &mode {
 3720                SelectMode::Character => {
 3721                    head = position.to_point(&display_map);
 3722                    tail = pending.tail().to_point(buffer);
 3723                }
 3724                SelectMode::Word(original_range) => {
 3725                    let offset = display_map
 3726                        .clip_point(position, Bias::Left)
 3727                        .to_offset(&display_map, Bias::Left);
 3728                    let original_range = original_range.to_offset(buffer);
 3729
 3730                    let head_offset = if buffer.is_inside_word(offset, None)
 3731                        || original_range.contains(&offset)
 3732                    {
 3733                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3734                        if word_range.start < original_range.start {
 3735                            word_range.start
 3736                        } else {
 3737                            word_range.end
 3738                        }
 3739                    } else {
 3740                        offset
 3741                    };
 3742
 3743                    head = head_offset.to_point(buffer);
 3744                    if head_offset <= original_range.start {
 3745                        tail = original_range.end.to_point(buffer);
 3746                    } else {
 3747                        tail = original_range.start.to_point(buffer);
 3748                    }
 3749                }
 3750                SelectMode::Line(original_range) => {
 3751                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3752
 3753                    let position = display_map
 3754                        .clip_point(position, Bias::Left)
 3755                        .to_point(&display_map);
 3756                    let line_start = display_map.prev_line_boundary(position).0;
 3757                    let next_line_start = buffer.clip_point(
 3758                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3759                        Bias::Left,
 3760                    );
 3761
 3762                    if line_start < original_range.start {
 3763                        head = line_start
 3764                    } else {
 3765                        head = next_line_start
 3766                    }
 3767
 3768                    if head <= original_range.start {
 3769                        tail = original_range.end;
 3770                    } else {
 3771                        tail = original_range.start;
 3772                    }
 3773                }
 3774                SelectMode::All => {
 3775                    return;
 3776                }
 3777            };
 3778
 3779            if head < tail {
 3780                pending.start = buffer.anchor_before(head);
 3781                pending.end = buffer.anchor_before(tail);
 3782                pending.reversed = true;
 3783            } else {
 3784                pending.start = buffer.anchor_before(tail);
 3785                pending.end = buffer.anchor_before(head);
 3786                pending.reversed = false;
 3787            }
 3788
 3789            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3790                s.set_pending(pending.clone(), mode);
 3791            });
 3792        } else {
 3793            log::error!("update_selection dispatched with no pending selection");
 3794            return;
 3795        }
 3796
 3797        self.apply_scroll_delta(scroll_delta, window, cx);
 3798        cx.notify();
 3799    }
 3800
 3801    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3802        self.columnar_selection_state.take();
 3803        if self.selections.pending_anchor().is_some() {
 3804            let selections = self.selections.all::<usize>(cx);
 3805            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3806                s.select(selections);
 3807                s.clear_pending();
 3808            });
 3809        }
 3810    }
 3811
 3812    fn select_columns(
 3813        &mut self,
 3814        head: DisplayPoint,
 3815        goal_column: u32,
 3816        display_map: &DisplaySnapshot,
 3817        window: &mut Window,
 3818        cx: &mut Context<Self>,
 3819    ) {
 3820        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3821            return;
 3822        };
 3823
 3824        let tail = match columnar_state {
 3825            ColumnarSelectionState::FromMouse {
 3826                selection_tail,
 3827                display_point,
 3828            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3829            ColumnarSelectionState::FromSelection { selection_tail } => {
 3830                selection_tail.to_display_point(display_map)
 3831            }
 3832        };
 3833
 3834        let start_row = cmp::min(tail.row(), head.row());
 3835        let end_row = cmp::max(tail.row(), head.row());
 3836        let start_column = cmp::min(tail.column(), goal_column);
 3837        let end_column = cmp::max(tail.column(), goal_column);
 3838        let reversed = start_column < tail.column();
 3839
 3840        let selection_ranges = (start_row.0..=end_row.0)
 3841            .map(DisplayRow)
 3842            .filter_map(|row| {
 3843                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3844                    || start_column <= display_map.line_len(row))
 3845                    && !display_map.is_block_line(row)
 3846                {
 3847                    let start = display_map
 3848                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3849                        .to_point(display_map);
 3850                    let end = display_map
 3851                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3852                        .to_point(display_map);
 3853                    if reversed {
 3854                        Some(end..start)
 3855                    } else {
 3856                        Some(start..end)
 3857                    }
 3858                } else {
 3859                    None
 3860                }
 3861            })
 3862            .collect::<Vec<_>>();
 3863
 3864        let ranges = match columnar_state {
 3865            ColumnarSelectionState::FromMouse { .. } => {
 3866                let mut non_empty_ranges = selection_ranges
 3867                    .iter()
 3868                    .filter(|selection_range| selection_range.start != selection_range.end)
 3869                    .peekable();
 3870                if non_empty_ranges.peek().is_some() {
 3871                    non_empty_ranges.cloned().collect()
 3872                } else {
 3873                    selection_ranges
 3874                }
 3875            }
 3876            _ => selection_ranges,
 3877        };
 3878
 3879        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3880            s.select_ranges(ranges);
 3881        });
 3882        cx.notify();
 3883    }
 3884
 3885    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3886        self.selections
 3887            .all_adjusted(cx)
 3888            .iter()
 3889            .any(|selection| !selection.is_empty())
 3890    }
 3891
 3892    pub fn has_pending_nonempty_selection(&self) -> bool {
 3893        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3894            Some(Selection { start, end, .. }) => start != end,
 3895            None => false,
 3896        };
 3897
 3898        pending_nonempty_selection
 3899            || (self.columnar_selection_state.is_some()
 3900                && self.selections.disjoint_anchors().len() > 1)
 3901    }
 3902
 3903    pub fn has_pending_selection(&self) -> bool {
 3904        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3905    }
 3906
 3907    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3908        self.selection_mark_mode = false;
 3909        self.selection_drag_state = SelectionDragState::None;
 3910
 3911        if self.clear_expanded_diff_hunks(cx) {
 3912            cx.notify();
 3913            return;
 3914        }
 3915        if self.dismiss_menus_and_popups(true, window, cx) {
 3916            return;
 3917        }
 3918
 3919        if self.mode.is_full()
 3920            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3921        {
 3922            return;
 3923        }
 3924
 3925        cx.propagate();
 3926    }
 3927
 3928    pub fn dismiss_menus_and_popups(
 3929        &mut self,
 3930        is_user_requested: bool,
 3931        window: &mut Window,
 3932        cx: &mut Context<Self>,
 3933    ) -> bool {
 3934        if self.take_rename(false, window, cx).is_some() {
 3935            return true;
 3936        }
 3937
 3938        if hide_hover(self, cx) {
 3939            return true;
 3940        }
 3941
 3942        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3943            return true;
 3944        }
 3945
 3946        if self.hide_context_menu(window, cx).is_some() {
 3947            return true;
 3948        }
 3949
 3950        if self.mouse_context_menu.take().is_some() {
 3951            return true;
 3952        }
 3953
 3954        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3955            return true;
 3956        }
 3957
 3958        if self.snippet_stack.pop().is_some() {
 3959            return true;
 3960        }
 3961
 3962        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3963            self.dismiss_diagnostics(cx);
 3964            return true;
 3965        }
 3966
 3967        false
 3968    }
 3969
 3970    fn linked_editing_ranges_for(
 3971        &self,
 3972        selection: Range<text::Anchor>,
 3973        cx: &App,
 3974    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3975        if self.linked_edit_ranges.is_empty() {
 3976            return None;
 3977        }
 3978        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3979            selection.end.buffer_id.and_then(|end_buffer_id| {
 3980                if selection.start.buffer_id != Some(end_buffer_id) {
 3981                    return None;
 3982                }
 3983                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3984                let snapshot = buffer.read(cx).snapshot();
 3985                self.linked_edit_ranges
 3986                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3987                    .map(|ranges| (ranges, snapshot, buffer))
 3988            })?;
 3989        use text::ToOffset as TO;
 3990        // find offset from the start of current range to current cursor position
 3991        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3992
 3993        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3994        let start_difference = start_offset - start_byte_offset;
 3995        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3996        let end_difference = end_offset - start_byte_offset;
 3997        // Current range has associated linked ranges.
 3998        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3999        for range in linked_ranges.iter() {
 4000            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4001            let end_offset = start_offset + end_difference;
 4002            let start_offset = start_offset + start_difference;
 4003            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4004                continue;
 4005            }
 4006            if self.selections.disjoint_anchor_ranges().any(|s| {
 4007                if s.start.buffer_id != selection.start.buffer_id
 4008                    || s.end.buffer_id != selection.end.buffer_id
 4009                {
 4010                    return false;
 4011                }
 4012                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4013                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4014            }) {
 4015                continue;
 4016            }
 4017            let start = buffer_snapshot.anchor_after(start_offset);
 4018            let end = buffer_snapshot.anchor_after(end_offset);
 4019            linked_edits
 4020                .entry(buffer.clone())
 4021                .or_default()
 4022                .push(start..end);
 4023        }
 4024        Some(linked_edits)
 4025    }
 4026
 4027    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4028        let text: Arc<str> = text.into();
 4029
 4030        if self.read_only(cx) {
 4031            return;
 4032        }
 4033
 4034        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4035
 4036        let selections = self.selections.all_adjusted(cx);
 4037        let mut bracket_inserted = false;
 4038        let mut edits = Vec::new();
 4039        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4040        let mut new_selections = Vec::with_capacity(selections.len());
 4041        let mut new_autoclose_regions = Vec::new();
 4042        let snapshot = self.buffer.read(cx).read(cx);
 4043        let mut clear_linked_edit_ranges = false;
 4044
 4045        for (selection, autoclose_region) in
 4046            self.selections_with_autoclose_regions(selections, &snapshot)
 4047        {
 4048            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4049                // Determine if the inserted text matches the opening or closing
 4050                // bracket of any of this language's bracket pairs.
 4051                let mut bracket_pair = None;
 4052                let mut is_bracket_pair_start = false;
 4053                let mut is_bracket_pair_end = false;
 4054                if !text.is_empty() {
 4055                    let mut bracket_pair_matching_end = None;
 4056                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4057                    //  and they are removing the character that triggered IME popup.
 4058                    for (pair, enabled) in scope.brackets() {
 4059                        if !pair.close && !pair.surround {
 4060                            continue;
 4061                        }
 4062
 4063                        if enabled && pair.start.ends_with(text.as_ref()) {
 4064                            let prefix_len = pair.start.len() - text.len();
 4065                            let preceding_text_matches_prefix = prefix_len == 0
 4066                                || (selection.start.column >= (prefix_len as u32)
 4067                                    && snapshot.contains_str_at(
 4068                                        Point::new(
 4069                                            selection.start.row,
 4070                                            selection.start.column - (prefix_len as u32),
 4071                                        ),
 4072                                        &pair.start[..prefix_len],
 4073                                    ));
 4074                            if preceding_text_matches_prefix {
 4075                                bracket_pair = Some(pair.clone());
 4076                                is_bracket_pair_start = true;
 4077                                break;
 4078                            }
 4079                        }
 4080                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4081                        {
 4082                            // take first bracket pair matching end, but don't break in case a later bracket
 4083                            // pair matches start
 4084                            bracket_pair_matching_end = Some(pair.clone());
 4085                        }
 4086                    }
 4087                    if let Some(end) = bracket_pair_matching_end
 4088                        && bracket_pair.is_none()
 4089                    {
 4090                        bracket_pair = Some(end);
 4091                        is_bracket_pair_end = true;
 4092                    }
 4093                }
 4094
 4095                if let Some(bracket_pair) = bracket_pair {
 4096                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4097                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4098                    let auto_surround =
 4099                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4100                    if selection.is_empty() {
 4101                        if is_bracket_pair_start {
 4102                            // If the inserted text is a suffix of an opening bracket and the
 4103                            // selection is preceded by the rest of the opening bracket, then
 4104                            // insert the closing bracket.
 4105                            let following_text_allows_autoclose = snapshot
 4106                                .chars_at(selection.start)
 4107                                .next()
 4108                                .is_none_or(|c| scope.should_autoclose_before(c));
 4109
 4110                            let preceding_text_allows_autoclose = selection.start.column == 0
 4111                                || snapshot
 4112                                    .reversed_chars_at(selection.start)
 4113                                    .next()
 4114                                    .is_none_or(|c| {
 4115                                        bracket_pair.start != bracket_pair.end
 4116                                            || !snapshot
 4117                                                .char_classifier_at(selection.start)
 4118                                                .is_word(c)
 4119                                    });
 4120
 4121                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4122                                && bracket_pair.start.len() == 1
 4123                            {
 4124                                let target = bracket_pair.start.chars().next().unwrap();
 4125                                let current_line_count = snapshot
 4126                                    .reversed_chars_at(selection.start)
 4127                                    .take_while(|&c| c != '\n')
 4128                                    .filter(|&c| c == target)
 4129                                    .count();
 4130                                current_line_count % 2 == 1
 4131                            } else {
 4132                                false
 4133                            };
 4134
 4135                            if autoclose
 4136                                && bracket_pair.close
 4137                                && following_text_allows_autoclose
 4138                                && preceding_text_allows_autoclose
 4139                                && !is_closing_quote
 4140                            {
 4141                                let anchor = snapshot.anchor_before(selection.end);
 4142                                new_selections.push((selection.map(|_| anchor), text.len()));
 4143                                new_autoclose_regions.push((
 4144                                    anchor,
 4145                                    text.len(),
 4146                                    selection.id,
 4147                                    bracket_pair.clone(),
 4148                                ));
 4149                                edits.push((
 4150                                    selection.range(),
 4151                                    format!("{}{}", text, bracket_pair.end).into(),
 4152                                ));
 4153                                bracket_inserted = true;
 4154                                continue;
 4155                            }
 4156                        }
 4157
 4158                        if let Some(region) = autoclose_region {
 4159                            // If the selection is followed by an auto-inserted closing bracket,
 4160                            // then don't insert that closing bracket again; just move the selection
 4161                            // past the closing bracket.
 4162                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4163                                && text.as_ref() == region.pair.end.as_str()
 4164                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4165                            if should_skip {
 4166                                let anchor = snapshot.anchor_after(selection.end);
 4167                                new_selections
 4168                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4169                                continue;
 4170                            }
 4171                        }
 4172
 4173                        let always_treat_brackets_as_autoclosed = snapshot
 4174                            .language_settings_at(selection.start, cx)
 4175                            .always_treat_brackets_as_autoclosed;
 4176                        if always_treat_brackets_as_autoclosed
 4177                            && is_bracket_pair_end
 4178                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4179                        {
 4180                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4181                            // and the inserted text is a closing bracket and the selection is followed
 4182                            // by the closing bracket then move the selection past the closing bracket.
 4183                            let anchor = snapshot.anchor_after(selection.end);
 4184                            new_selections.push((selection.map(|_| anchor), text.len()));
 4185                            continue;
 4186                        }
 4187                    }
 4188                    // If an opening bracket is 1 character long and is typed while
 4189                    // text is selected, then surround that text with the bracket pair.
 4190                    else if auto_surround
 4191                        && bracket_pair.surround
 4192                        && is_bracket_pair_start
 4193                        && bracket_pair.start.chars().count() == 1
 4194                    {
 4195                        edits.push((selection.start..selection.start, text.clone()));
 4196                        edits.push((
 4197                            selection.end..selection.end,
 4198                            bracket_pair.end.as_str().into(),
 4199                        ));
 4200                        bracket_inserted = true;
 4201                        new_selections.push((
 4202                            Selection {
 4203                                id: selection.id,
 4204                                start: snapshot.anchor_after(selection.start),
 4205                                end: snapshot.anchor_before(selection.end),
 4206                                reversed: selection.reversed,
 4207                                goal: selection.goal,
 4208                            },
 4209                            0,
 4210                        ));
 4211                        continue;
 4212                    }
 4213                }
 4214            }
 4215
 4216            if self.auto_replace_emoji_shortcode
 4217                && selection.is_empty()
 4218                && text.as_ref().ends_with(':')
 4219                && let Some(possible_emoji_short_code) =
 4220                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4221                && !possible_emoji_short_code.is_empty()
 4222                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4223            {
 4224                let emoji_shortcode_start = Point::new(
 4225                    selection.start.row,
 4226                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4227                );
 4228
 4229                // Remove shortcode from buffer
 4230                edits.push((
 4231                    emoji_shortcode_start..selection.start,
 4232                    "".to_string().into(),
 4233                ));
 4234                new_selections.push((
 4235                    Selection {
 4236                        id: selection.id,
 4237                        start: snapshot.anchor_after(emoji_shortcode_start),
 4238                        end: snapshot.anchor_before(selection.start),
 4239                        reversed: selection.reversed,
 4240                        goal: selection.goal,
 4241                    },
 4242                    0,
 4243                ));
 4244
 4245                // Insert emoji
 4246                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4247                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4248                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4249
 4250                continue;
 4251            }
 4252
 4253            // If not handling any auto-close operation, then just replace the selected
 4254            // text with the given input and move the selection to the end of the
 4255            // newly inserted text.
 4256            let anchor = snapshot.anchor_after(selection.end);
 4257            if !self.linked_edit_ranges.is_empty() {
 4258                let start_anchor = snapshot.anchor_before(selection.start);
 4259
 4260                let is_word_char = text.chars().next().is_none_or(|char| {
 4261                    let classifier = snapshot
 4262                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4263                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4264                    classifier.is_word(char)
 4265                });
 4266
 4267                if is_word_char {
 4268                    if let Some(ranges) = self
 4269                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4270                    {
 4271                        for (buffer, edits) in ranges {
 4272                            linked_edits
 4273                                .entry(buffer.clone())
 4274                                .or_default()
 4275                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4276                        }
 4277                    }
 4278                } else {
 4279                    clear_linked_edit_ranges = true;
 4280                }
 4281            }
 4282
 4283            new_selections.push((selection.map(|_| anchor), 0));
 4284            edits.push((selection.start..selection.end, text.clone()));
 4285        }
 4286
 4287        drop(snapshot);
 4288
 4289        self.transact(window, cx, |this, window, cx| {
 4290            if clear_linked_edit_ranges {
 4291                this.linked_edit_ranges.clear();
 4292            }
 4293            let initial_buffer_versions =
 4294                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4295
 4296            this.buffer.update(cx, |buffer, cx| {
 4297                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4298            });
 4299            for (buffer, edits) in linked_edits {
 4300                buffer.update(cx, |buffer, cx| {
 4301                    let snapshot = buffer.snapshot();
 4302                    let edits = edits
 4303                        .into_iter()
 4304                        .map(|(range, text)| {
 4305                            use text::ToPoint as TP;
 4306                            let end_point = TP::to_point(&range.end, &snapshot);
 4307                            let start_point = TP::to_point(&range.start, &snapshot);
 4308                            (start_point..end_point, text)
 4309                        })
 4310                        .sorted_by_key(|(range, _)| range.start);
 4311                    buffer.edit(edits, None, cx);
 4312                })
 4313            }
 4314            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4315            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4316            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4317            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4318                .zip(new_selection_deltas)
 4319                .map(|(selection, delta)| Selection {
 4320                    id: selection.id,
 4321                    start: selection.start + delta,
 4322                    end: selection.end + delta,
 4323                    reversed: selection.reversed,
 4324                    goal: SelectionGoal::None,
 4325                })
 4326                .collect::<Vec<_>>();
 4327
 4328            let mut i = 0;
 4329            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4330                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4331                let start = map.buffer_snapshot.anchor_before(position);
 4332                let end = map.buffer_snapshot.anchor_after(position);
 4333                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4334                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4335                        Ordering::Less => i += 1,
 4336                        Ordering::Greater => break,
 4337                        Ordering::Equal => {
 4338                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4339                                Ordering::Less => i += 1,
 4340                                Ordering::Equal => break,
 4341                                Ordering::Greater => break,
 4342                            }
 4343                        }
 4344                    }
 4345                }
 4346                this.autoclose_regions.insert(
 4347                    i,
 4348                    AutocloseRegion {
 4349                        selection_id,
 4350                        range: start..end,
 4351                        pair,
 4352                    },
 4353                );
 4354            }
 4355
 4356            let had_active_edit_prediction = this.has_active_edit_prediction();
 4357            this.change_selections(
 4358                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4359                window,
 4360                cx,
 4361                |s| s.select(new_selections),
 4362            );
 4363
 4364            if !bracket_inserted
 4365                && let Some(on_type_format_task) =
 4366                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4367            {
 4368                on_type_format_task.detach_and_log_err(cx);
 4369            }
 4370
 4371            let editor_settings = EditorSettings::get_global(cx);
 4372            if bracket_inserted
 4373                && (editor_settings.auto_signature_help
 4374                    || editor_settings.show_signature_help_after_edits)
 4375            {
 4376                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4377            }
 4378
 4379            let trigger_in_words =
 4380                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4381            if this.hard_wrap.is_some() {
 4382                let latest: Range<Point> = this.selections.newest(cx).range();
 4383                if latest.is_empty()
 4384                    && this
 4385                        .buffer()
 4386                        .read(cx)
 4387                        .snapshot(cx)
 4388                        .line_len(MultiBufferRow(latest.start.row))
 4389                        == latest.start.column
 4390                {
 4391                    this.rewrap_impl(
 4392                        RewrapOptions {
 4393                            override_language_settings: true,
 4394                            preserve_existing_whitespace: true,
 4395                        },
 4396                        cx,
 4397                    )
 4398                }
 4399            }
 4400            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4401            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4402            this.refresh_edit_prediction(true, false, window, cx);
 4403            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4404        });
 4405    }
 4406
 4407    fn find_possible_emoji_shortcode_at_position(
 4408        snapshot: &MultiBufferSnapshot,
 4409        position: Point,
 4410    ) -> Option<String> {
 4411        let mut chars = Vec::new();
 4412        let mut found_colon = false;
 4413        for char in snapshot.reversed_chars_at(position).take(100) {
 4414            // Found a possible emoji shortcode in the middle of the buffer
 4415            if found_colon {
 4416                if char.is_whitespace() {
 4417                    chars.reverse();
 4418                    return Some(chars.iter().collect());
 4419                }
 4420                // If the previous character is not a whitespace, we are in the middle of a word
 4421                // and we only want to complete the shortcode if the word is made up of other emojis
 4422                let mut containing_word = String::new();
 4423                for ch in snapshot
 4424                    .reversed_chars_at(position)
 4425                    .skip(chars.len() + 1)
 4426                    .take(100)
 4427                {
 4428                    if ch.is_whitespace() {
 4429                        break;
 4430                    }
 4431                    containing_word.push(ch);
 4432                }
 4433                let containing_word = containing_word.chars().rev().collect::<String>();
 4434                if util::word_consists_of_emojis(containing_word.as_str()) {
 4435                    chars.reverse();
 4436                    return Some(chars.iter().collect());
 4437                }
 4438            }
 4439
 4440            if char.is_whitespace() || !char.is_ascii() {
 4441                return None;
 4442            }
 4443            if char == ':' {
 4444                found_colon = true;
 4445            } else {
 4446                chars.push(char);
 4447            }
 4448        }
 4449        // Found a possible emoji shortcode at the beginning of the buffer
 4450        chars.reverse();
 4451        Some(chars.iter().collect())
 4452    }
 4453
 4454    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4455        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4456        self.transact(window, cx, |this, window, cx| {
 4457            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4458                let selections = this.selections.all::<usize>(cx);
 4459                let multi_buffer = this.buffer.read(cx);
 4460                let buffer = multi_buffer.snapshot(cx);
 4461                selections
 4462                    .iter()
 4463                    .map(|selection| {
 4464                        let start_point = selection.start.to_point(&buffer);
 4465                        let mut existing_indent =
 4466                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4467                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4468                        let start = selection.start;
 4469                        let end = selection.end;
 4470                        let selection_is_empty = start == end;
 4471                        let language_scope = buffer.language_scope_at(start);
 4472                        let (
 4473                            comment_delimiter,
 4474                            doc_delimiter,
 4475                            insert_extra_newline,
 4476                            indent_on_newline,
 4477                            indent_on_extra_newline,
 4478                        ) = if let Some(language) = &language_scope {
 4479                            let mut insert_extra_newline =
 4480                                insert_extra_newline_brackets(&buffer, start..end, language)
 4481                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4482
 4483                            // Comment extension on newline is allowed only for cursor selections
 4484                            let comment_delimiter = maybe!({
 4485                                if !selection_is_empty {
 4486                                    return None;
 4487                                }
 4488
 4489                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4490                                    return None;
 4491                                }
 4492
 4493                                let delimiters = language.line_comment_prefixes();
 4494                                let max_len_of_delimiter =
 4495                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4496                                let (snapshot, range) =
 4497                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4498
 4499                                let num_of_whitespaces = snapshot
 4500                                    .chars_for_range(range.clone())
 4501                                    .take_while(|c| c.is_whitespace())
 4502                                    .count();
 4503                                let comment_candidate = snapshot
 4504                                    .chars_for_range(range.clone())
 4505                                    .skip(num_of_whitespaces)
 4506                                    .take(max_len_of_delimiter)
 4507                                    .collect::<String>();
 4508                                let (delimiter, trimmed_len) = delimiters
 4509                                    .iter()
 4510                                    .filter_map(|delimiter| {
 4511                                        let prefix = delimiter.trim_end();
 4512                                        if comment_candidate.starts_with(prefix) {
 4513                                            Some((delimiter, prefix.len()))
 4514                                        } else {
 4515                                            None
 4516                                        }
 4517                                    })
 4518                                    .max_by_key(|(_, len)| *len)?;
 4519
 4520                                if let Some(BlockCommentConfig {
 4521                                    start: block_start, ..
 4522                                }) = language.block_comment()
 4523                                {
 4524                                    let block_start_trimmed = block_start.trim_end();
 4525                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4526                                        let line_content = snapshot
 4527                                            .chars_for_range(range)
 4528                                            .skip(num_of_whitespaces)
 4529                                            .take(block_start_trimmed.len())
 4530                                            .collect::<String>();
 4531
 4532                                        if line_content.starts_with(block_start_trimmed) {
 4533                                            return None;
 4534                                        }
 4535                                    }
 4536                                }
 4537
 4538                                let cursor_is_placed_after_comment_marker =
 4539                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4540                                if cursor_is_placed_after_comment_marker {
 4541                                    Some(delimiter.clone())
 4542                                } else {
 4543                                    None
 4544                                }
 4545                            });
 4546
 4547                            let mut indent_on_newline = IndentSize::spaces(0);
 4548                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4549
 4550                            let doc_delimiter = maybe!({
 4551                                if !selection_is_empty {
 4552                                    return None;
 4553                                }
 4554
 4555                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4556                                    return None;
 4557                                }
 4558
 4559                                let BlockCommentConfig {
 4560                                    start: start_tag,
 4561                                    end: end_tag,
 4562                                    prefix: delimiter,
 4563                                    tab_size: len,
 4564                                } = language.documentation_comment()?;
 4565                                let is_within_block_comment = buffer
 4566                                    .language_scope_at(start_point)
 4567                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4568                                if !is_within_block_comment {
 4569                                    return None;
 4570                                }
 4571
 4572                                let (snapshot, range) =
 4573                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4574
 4575                                let num_of_whitespaces = snapshot
 4576                                    .chars_for_range(range.clone())
 4577                                    .take_while(|c| c.is_whitespace())
 4578                                    .count();
 4579
 4580                                // 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.
 4581                                let column = start_point.column;
 4582                                let cursor_is_after_start_tag = {
 4583                                    let start_tag_len = start_tag.len();
 4584                                    let start_tag_line = snapshot
 4585                                        .chars_for_range(range.clone())
 4586                                        .skip(num_of_whitespaces)
 4587                                        .take(start_tag_len)
 4588                                        .collect::<String>();
 4589                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4590                                        num_of_whitespaces + start_tag_len <= column as usize
 4591                                    } else {
 4592                                        false
 4593                                    }
 4594                                };
 4595
 4596                                let cursor_is_after_delimiter = {
 4597                                    let delimiter_trim = delimiter.trim_end();
 4598                                    let delimiter_line = snapshot
 4599                                        .chars_for_range(range.clone())
 4600                                        .skip(num_of_whitespaces)
 4601                                        .take(delimiter_trim.len())
 4602                                        .collect::<String>();
 4603                                    if delimiter_line.starts_with(delimiter_trim) {
 4604                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4605                                    } else {
 4606                                        false
 4607                                    }
 4608                                };
 4609
 4610                                let cursor_is_before_end_tag_if_exists = {
 4611                                    let mut char_position = 0u32;
 4612                                    let mut end_tag_offset = None;
 4613
 4614                                    'outer: for chunk in snapshot.text_for_range(range) {
 4615                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4616                                            let chars_before_match =
 4617                                                chunk[..byte_pos].chars().count() as u32;
 4618                                            end_tag_offset =
 4619                                                Some(char_position + chars_before_match);
 4620                                            break 'outer;
 4621                                        }
 4622                                        char_position += chunk.chars().count() as u32;
 4623                                    }
 4624
 4625                                    if let Some(end_tag_offset) = end_tag_offset {
 4626                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4627                                        if cursor_is_after_start_tag {
 4628                                            if cursor_is_before_end_tag {
 4629                                                insert_extra_newline = true;
 4630                                            }
 4631                                            let cursor_is_at_start_of_end_tag =
 4632                                                column == end_tag_offset;
 4633                                            if cursor_is_at_start_of_end_tag {
 4634                                                indent_on_extra_newline.len = *len;
 4635                                            }
 4636                                        }
 4637                                        cursor_is_before_end_tag
 4638                                    } else {
 4639                                        true
 4640                                    }
 4641                                };
 4642
 4643                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4644                                    && cursor_is_before_end_tag_if_exists
 4645                                {
 4646                                    if cursor_is_after_start_tag {
 4647                                        indent_on_newline.len = *len;
 4648                                    }
 4649                                    Some(delimiter.clone())
 4650                                } else {
 4651                                    None
 4652                                }
 4653                            });
 4654
 4655                            (
 4656                                comment_delimiter,
 4657                                doc_delimiter,
 4658                                insert_extra_newline,
 4659                                indent_on_newline,
 4660                                indent_on_extra_newline,
 4661                            )
 4662                        } else {
 4663                            (
 4664                                None,
 4665                                None,
 4666                                false,
 4667                                IndentSize::default(),
 4668                                IndentSize::default(),
 4669                            )
 4670                        };
 4671
 4672                        let prevent_auto_indent = doc_delimiter.is_some();
 4673                        let delimiter = comment_delimiter.or(doc_delimiter);
 4674
 4675                        let capacity_for_delimiter =
 4676                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4677                        let mut new_text = String::with_capacity(
 4678                            1 + capacity_for_delimiter
 4679                                + existing_indent.len as usize
 4680                                + indent_on_newline.len as usize
 4681                                + indent_on_extra_newline.len as usize,
 4682                        );
 4683                        new_text.push('\n');
 4684                        new_text.extend(existing_indent.chars());
 4685                        new_text.extend(indent_on_newline.chars());
 4686
 4687                        if let Some(delimiter) = &delimiter {
 4688                            new_text.push_str(delimiter);
 4689                        }
 4690
 4691                        if insert_extra_newline {
 4692                            new_text.push('\n');
 4693                            new_text.extend(existing_indent.chars());
 4694                            new_text.extend(indent_on_extra_newline.chars());
 4695                        }
 4696
 4697                        let anchor = buffer.anchor_after(end);
 4698                        let new_selection = selection.map(|_| anchor);
 4699                        (
 4700                            ((start..end, new_text), prevent_auto_indent),
 4701                            (insert_extra_newline, new_selection),
 4702                        )
 4703                    })
 4704                    .unzip()
 4705            };
 4706
 4707            let mut auto_indent_edits = Vec::new();
 4708            let mut edits = Vec::new();
 4709            for (edit, prevent_auto_indent) in edits_with_flags {
 4710                if prevent_auto_indent {
 4711                    edits.push(edit);
 4712                } else {
 4713                    auto_indent_edits.push(edit);
 4714                }
 4715            }
 4716            if !edits.is_empty() {
 4717                this.edit(edits, cx);
 4718            }
 4719            if !auto_indent_edits.is_empty() {
 4720                this.edit_with_autoindent(auto_indent_edits, cx);
 4721            }
 4722
 4723            let buffer = this.buffer.read(cx).snapshot(cx);
 4724            let new_selections = selection_info
 4725                .into_iter()
 4726                .map(|(extra_newline_inserted, new_selection)| {
 4727                    let mut cursor = new_selection.end.to_point(&buffer);
 4728                    if extra_newline_inserted {
 4729                        cursor.row -= 1;
 4730                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4731                    }
 4732                    new_selection.map(|_| cursor)
 4733                })
 4734                .collect();
 4735
 4736            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4737            this.refresh_edit_prediction(true, false, window, cx);
 4738        });
 4739    }
 4740
 4741    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4742        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4743
 4744        let buffer = self.buffer.read(cx);
 4745        let snapshot = buffer.snapshot(cx);
 4746
 4747        let mut edits = Vec::new();
 4748        let mut rows = Vec::new();
 4749
 4750        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4751            let cursor = selection.head();
 4752            let row = cursor.row;
 4753
 4754            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4755
 4756            let newline = "\n".to_string();
 4757            edits.push((start_of_line..start_of_line, newline));
 4758
 4759            rows.push(row + rows_inserted as u32);
 4760        }
 4761
 4762        self.transact(window, cx, |editor, window, cx| {
 4763            editor.edit(edits, cx);
 4764
 4765            editor.change_selections(Default::default(), window, cx, |s| {
 4766                let mut index = 0;
 4767                s.move_cursors_with(|map, _, _| {
 4768                    let row = rows[index];
 4769                    index += 1;
 4770
 4771                    let point = Point::new(row, 0);
 4772                    let boundary = map.next_line_boundary(point).1;
 4773                    let clipped = map.clip_point(boundary, Bias::Left);
 4774
 4775                    (clipped, SelectionGoal::None)
 4776                });
 4777            });
 4778
 4779            let mut indent_edits = Vec::new();
 4780            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4781            for row in rows {
 4782                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4783                for (row, indent) in indents {
 4784                    if indent.len == 0 {
 4785                        continue;
 4786                    }
 4787
 4788                    let text = match indent.kind {
 4789                        IndentKind::Space => " ".repeat(indent.len as usize),
 4790                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4791                    };
 4792                    let point = Point::new(row.0, 0);
 4793                    indent_edits.push((point..point, text));
 4794                }
 4795            }
 4796            editor.edit(indent_edits, cx);
 4797        });
 4798    }
 4799
 4800    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4801        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4802
 4803        let buffer = self.buffer.read(cx);
 4804        let snapshot = buffer.snapshot(cx);
 4805
 4806        let mut edits = Vec::new();
 4807        let mut rows = Vec::new();
 4808        let mut rows_inserted = 0;
 4809
 4810        for selection in self.selections.all_adjusted(cx) {
 4811            let cursor = selection.head();
 4812            let row = cursor.row;
 4813
 4814            let point = Point::new(row + 1, 0);
 4815            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4816
 4817            let newline = "\n".to_string();
 4818            edits.push((start_of_line..start_of_line, newline));
 4819
 4820            rows_inserted += 1;
 4821            rows.push(row + rows_inserted);
 4822        }
 4823
 4824        self.transact(window, cx, |editor, window, cx| {
 4825            editor.edit(edits, cx);
 4826
 4827            editor.change_selections(Default::default(), window, cx, |s| {
 4828                let mut index = 0;
 4829                s.move_cursors_with(|map, _, _| {
 4830                    let row = rows[index];
 4831                    index += 1;
 4832
 4833                    let point = Point::new(row, 0);
 4834                    let boundary = map.next_line_boundary(point).1;
 4835                    let clipped = map.clip_point(boundary, Bias::Left);
 4836
 4837                    (clipped, SelectionGoal::None)
 4838                });
 4839            });
 4840
 4841            let mut indent_edits = Vec::new();
 4842            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4843            for row in rows {
 4844                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4845                for (row, indent) in indents {
 4846                    if indent.len == 0 {
 4847                        continue;
 4848                    }
 4849
 4850                    let text = match indent.kind {
 4851                        IndentKind::Space => " ".repeat(indent.len as usize),
 4852                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4853                    };
 4854                    let point = Point::new(row.0, 0);
 4855                    indent_edits.push((point..point, text));
 4856                }
 4857            }
 4858            editor.edit(indent_edits, cx);
 4859        });
 4860    }
 4861
 4862    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4863        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4864            original_indent_columns: Vec::new(),
 4865        });
 4866        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4867    }
 4868
 4869    fn insert_with_autoindent_mode(
 4870        &mut self,
 4871        text: &str,
 4872        autoindent_mode: Option<AutoindentMode>,
 4873        window: &mut Window,
 4874        cx: &mut Context<Self>,
 4875    ) {
 4876        if self.read_only(cx) {
 4877            return;
 4878        }
 4879
 4880        let text: Arc<str> = text.into();
 4881        self.transact(window, cx, |this, window, cx| {
 4882            let old_selections = this.selections.all_adjusted(cx);
 4883            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4884                let anchors = {
 4885                    let snapshot = buffer.read(cx);
 4886                    old_selections
 4887                        .iter()
 4888                        .map(|s| {
 4889                            let anchor = snapshot.anchor_after(s.head());
 4890                            s.map(|_| anchor)
 4891                        })
 4892                        .collect::<Vec<_>>()
 4893                };
 4894                buffer.edit(
 4895                    old_selections
 4896                        .iter()
 4897                        .map(|s| (s.start..s.end, text.clone())),
 4898                    autoindent_mode,
 4899                    cx,
 4900                );
 4901                anchors
 4902            });
 4903
 4904            this.change_selections(Default::default(), window, cx, |s| {
 4905                s.select_anchors(selection_anchors);
 4906            });
 4907
 4908            cx.notify();
 4909        });
 4910    }
 4911
 4912    fn trigger_completion_on_input(
 4913        &mut self,
 4914        text: &str,
 4915        trigger_in_words: bool,
 4916        window: &mut Window,
 4917        cx: &mut Context<Self>,
 4918    ) {
 4919        let completions_source = self
 4920            .context_menu
 4921            .borrow()
 4922            .as_ref()
 4923            .and_then(|menu| match menu {
 4924                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4925                CodeContextMenu::CodeActions(_) => None,
 4926            });
 4927
 4928        match completions_source {
 4929            Some(CompletionsMenuSource::Words { .. }) => {
 4930                self.open_or_update_completions_menu(
 4931                    Some(CompletionsMenuSource::Words {
 4932                        ignore_threshold: false,
 4933                    }),
 4934                    None,
 4935                    window,
 4936                    cx,
 4937                );
 4938            }
 4939            Some(CompletionsMenuSource::Normal)
 4940            | Some(CompletionsMenuSource::SnippetChoices)
 4941            | None
 4942                if self.is_completion_trigger(
 4943                    text,
 4944                    trigger_in_words,
 4945                    completions_source.is_some(),
 4946                    cx,
 4947                ) =>
 4948            {
 4949                self.show_completions(
 4950                    &ShowCompletions {
 4951                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4952                    },
 4953                    window,
 4954                    cx,
 4955                )
 4956            }
 4957            _ => {
 4958                self.hide_context_menu(window, cx);
 4959            }
 4960        }
 4961    }
 4962
 4963    fn is_completion_trigger(
 4964        &self,
 4965        text: &str,
 4966        trigger_in_words: bool,
 4967        menu_is_open: bool,
 4968        cx: &mut Context<Self>,
 4969    ) -> bool {
 4970        let position = self.selections.newest_anchor().head();
 4971        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4972            return false;
 4973        };
 4974
 4975        if let Some(completion_provider) = &self.completion_provider {
 4976            completion_provider.is_completion_trigger(
 4977                &buffer,
 4978                position.text_anchor,
 4979                text,
 4980                trigger_in_words,
 4981                menu_is_open,
 4982                cx,
 4983            )
 4984        } else {
 4985            false
 4986        }
 4987    }
 4988
 4989    /// If any empty selections is touching the start of its innermost containing autoclose
 4990    /// region, expand it to select the brackets.
 4991    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4992        let selections = self.selections.all::<usize>(cx);
 4993        let buffer = self.buffer.read(cx).read(cx);
 4994        let new_selections = self
 4995            .selections_with_autoclose_regions(selections, &buffer)
 4996            .map(|(mut selection, region)| {
 4997                if !selection.is_empty() {
 4998                    return selection;
 4999                }
 5000
 5001                if let Some(region) = region {
 5002                    let mut range = region.range.to_offset(&buffer);
 5003                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5004                        range.start -= region.pair.start.len();
 5005                        if buffer.contains_str_at(range.start, &region.pair.start)
 5006                            && buffer.contains_str_at(range.end, &region.pair.end)
 5007                        {
 5008                            range.end += region.pair.end.len();
 5009                            selection.start = range.start;
 5010                            selection.end = range.end;
 5011
 5012                            return selection;
 5013                        }
 5014                    }
 5015                }
 5016
 5017                let always_treat_brackets_as_autoclosed = buffer
 5018                    .language_settings_at(selection.start, cx)
 5019                    .always_treat_brackets_as_autoclosed;
 5020
 5021                if !always_treat_brackets_as_autoclosed {
 5022                    return selection;
 5023                }
 5024
 5025                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5026                    for (pair, enabled) in scope.brackets() {
 5027                        if !enabled || !pair.close {
 5028                            continue;
 5029                        }
 5030
 5031                        if buffer.contains_str_at(selection.start, &pair.end) {
 5032                            let pair_start_len = pair.start.len();
 5033                            if buffer.contains_str_at(
 5034                                selection.start.saturating_sub(pair_start_len),
 5035                                &pair.start,
 5036                            ) {
 5037                                selection.start -= pair_start_len;
 5038                                selection.end += pair.end.len();
 5039
 5040                                return selection;
 5041                            }
 5042                        }
 5043                    }
 5044                }
 5045
 5046                selection
 5047            })
 5048            .collect();
 5049
 5050        drop(buffer);
 5051        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5052            selections.select(new_selections)
 5053        });
 5054    }
 5055
 5056    /// Iterate the given selections, and for each one, find the smallest surrounding
 5057    /// autoclose region. This uses the ordering of the selections and the autoclose
 5058    /// regions to avoid repeated comparisons.
 5059    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5060        &'a self,
 5061        selections: impl IntoIterator<Item = Selection<D>>,
 5062        buffer: &'a MultiBufferSnapshot,
 5063    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5064        let mut i = 0;
 5065        let mut regions = self.autoclose_regions.as_slice();
 5066        selections.into_iter().map(move |selection| {
 5067            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5068
 5069            let mut enclosing = None;
 5070            while let Some(pair_state) = regions.get(i) {
 5071                if pair_state.range.end.to_offset(buffer) < range.start {
 5072                    regions = &regions[i + 1..];
 5073                    i = 0;
 5074                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5075                    break;
 5076                } else {
 5077                    if pair_state.selection_id == selection.id {
 5078                        enclosing = Some(pair_state);
 5079                    }
 5080                    i += 1;
 5081                }
 5082            }
 5083
 5084            (selection, enclosing)
 5085        })
 5086    }
 5087
 5088    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5089    fn invalidate_autoclose_regions(
 5090        &mut self,
 5091        mut selections: &[Selection<Anchor>],
 5092        buffer: &MultiBufferSnapshot,
 5093    ) {
 5094        self.autoclose_regions.retain(|state| {
 5095            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5096                return false;
 5097            }
 5098
 5099            let mut i = 0;
 5100            while let Some(selection) = selections.get(i) {
 5101                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5102                    selections = &selections[1..];
 5103                    continue;
 5104                }
 5105                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5106                    break;
 5107                }
 5108                if selection.id == state.selection_id {
 5109                    return true;
 5110                } else {
 5111                    i += 1;
 5112                }
 5113            }
 5114            false
 5115        });
 5116    }
 5117
 5118    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5119        let offset = position.to_offset(buffer);
 5120        let (word_range, kind) =
 5121            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5122        if offset > word_range.start && kind == Some(CharKind::Word) {
 5123            Some(
 5124                buffer
 5125                    .text_for_range(word_range.start..offset)
 5126                    .collect::<String>(),
 5127            )
 5128        } else {
 5129            None
 5130        }
 5131    }
 5132
 5133    pub fn toggle_inline_values(
 5134        &mut self,
 5135        _: &ToggleInlineValues,
 5136        _: &mut Window,
 5137        cx: &mut Context<Self>,
 5138    ) {
 5139        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5140
 5141        self.refresh_inline_values(cx);
 5142    }
 5143
 5144    pub fn toggle_inlay_hints(
 5145        &mut self,
 5146        _: &ToggleInlayHints,
 5147        _: &mut Window,
 5148        cx: &mut Context<Self>,
 5149    ) {
 5150        self.refresh_inlay_hints(
 5151            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5152            cx,
 5153        );
 5154    }
 5155
 5156    pub fn inlay_hints_enabled(&self) -> bool {
 5157        self.inlay_hint_cache.enabled
 5158    }
 5159
 5160    pub fn inline_values_enabled(&self) -> bool {
 5161        self.inline_value_cache.enabled
 5162    }
 5163
 5164    #[cfg(any(test, feature = "test-support"))]
 5165    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5166        self.display_map
 5167            .read(cx)
 5168            .current_inlays()
 5169            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5170            .cloned()
 5171            .collect()
 5172    }
 5173
 5174    #[cfg(any(test, feature = "test-support"))]
 5175    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5176        self.display_map
 5177            .read(cx)
 5178            .current_inlays()
 5179            .cloned()
 5180            .collect()
 5181    }
 5182
 5183    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5184        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5185            return;
 5186        }
 5187
 5188        let reason_description = reason.description();
 5189        let ignore_debounce = matches!(
 5190            reason,
 5191            InlayHintRefreshReason::SettingsChange(_)
 5192                | InlayHintRefreshReason::Toggle(_)
 5193                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5194                | InlayHintRefreshReason::ModifiersChanged(_)
 5195        );
 5196        let (invalidate_cache, required_languages) = match reason {
 5197            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5198                match self.inlay_hint_cache.modifiers_override(enabled) {
 5199                    Some(enabled) => {
 5200                        if enabled {
 5201                            (InvalidationStrategy::RefreshRequested, None)
 5202                        } else {
 5203                            self.splice_inlays(
 5204                                &self
 5205                                    .visible_inlay_hints(cx)
 5206                                    .iter()
 5207                                    .map(|inlay| inlay.id)
 5208                                    .collect::<Vec<InlayId>>(),
 5209                                Vec::new(),
 5210                                cx,
 5211                            );
 5212                            return;
 5213                        }
 5214                    }
 5215                    None => return,
 5216                }
 5217            }
 5218            InlayHintRefreshReason::Toggle(enabled) => {
 5219                if self.inlay_hint_cache.toggle(enabled) {
 5220                    if enabled {
 5221                        (InvalidationStrategy::RefreshRequested, None)
 5222                    } else {
 5223                        self.splice_inlays(
 5224                            &self
 5225                                .visible_inlay_hints(cx)
 5226                                .iter()
 5227                                .map(|inlay| inlay.id)
 5228                                .collect::<Vec<InlayId>>(),
 5229                            Vec::new(),
 5230                            cx,
 5231                        );
 5232                        return;
 5233                    }
 5234                } else {
 5235                    return;
 5236                }
 5237            }
 5238            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5239                match self.inlay_hint_cache.update_settings(
 5240                    &self.buffer,
 5241                    new_settings,
 5242                    self.visible_inlay_hints(cx),
 5243                    cx,
 5244                ) {
 5245                    ControlFlow::Break(Some(InlaySplice {
 5246                        to_remove,
 5247                        to_insert,
 5248                    })) => {
 5249                        self.splice_inlays(&to_remove, to_insert, cx);
 5250                        return;
 5251                    }
 5252                    ControlFlow::Break(None) => return,
 5253                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5254                }
 5255            }
 5256            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5257                if let Some(InlaySplice {
 5258                    to_remove,
 5259                    to_insert,
 5260                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5261                {
 5262                    self.splice_inlays(&to_remove, to_insert, cx);
 5263                }
 5264                self.display_map.update(cx, |display_map, _| {
 5265                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5266                });
 5267                return;
 5268            }
 5269            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5270            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5271                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5272            }
 5273            InlayHintRefreshReason::RefreshRequested => {
 5274                (InvalidationStrategy::RefreshRequested, None)
 5275            }
 5276        };
 5277
 5278        if let Some(InlaySplice {
 5279            to_remove,
 5280            to_insert,
 5281        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5282            reason_description,
 5283            self.visible_excerpts(required_languages.as_ref(), cx),
 5284            invalidate_cache,
 5285            ignore_debounce,
 5286            cx,
 5287        ) {
 5288            self.splice_inlays(&to_remove, to_insert, cx);
 5289        }
 5290    }
 5291
 5292    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5293        self.display_map
 5294            .read(cx)
 5295            .current_inlays()
 5296            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5297            .cloned()
 5298            .collect()
 5299    }
 5300
 5301    pub fn visible_excerpts(
 5302        &self,
 5303        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5304        cx: &mut Context<Editor>,
 5305    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5306        let Some(project) = self.project() else {
 5307            return HashMap::default();
 5308        };
 5309        let project = project.read(cx);
 5310        let multi_buffer = self.buffer().read(cx);
 5311        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5312        let multi_buffer_visible_start = self
 5313            .scroll_manager
 5314            .anchor()
 5315            .anchor
 5316            .to_point(&multi_buffer_snapshot);
 5317        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5318            multi_buffer_visible_start
 5319                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5320            Bias::Left,
 5321        );
 5322        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5323        multi_buffer_snapshot
 5324            .range_to_buffer_ranges(multi_buffer_visible_range)
 5325            .into_iter()
 5326            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5327            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5328                let buffer_file = project::File::from_dyn(buffer.file())?;
 5329                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5330                let worktree_entry = buffer_worktree
 5331                    .read(cx)
 5332                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5333                if worktree_entry.is_ignored {
 5334                    return None;
 5335                }
 5336
 5337                let language = buffer.language()?;
 5338                if let Some(restrict_to_languages) = restrict_to_languages
 5339                    && !restrict_to_languages.contains(language)
 5340                {
 5341                    return None;
 5342                }
 5343                Some((
 5344                    excerpt_id,
 5345                    (
 5346                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5347                        buffer.version().clone(),
 5348                        excerpt_visible_range,
 5349                    ),
 5350                ))
 5351            })
 5352            .collect()
 5353    }
 5354
 5355    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5356        TextLayoutDetails {
 5357            text_system: window.text_system().clone(),
 5358            editor_style: self.style.clone().unwrap(),
 5359            rem_size: window.rem_size(),
 5360            scroll_anchor: self.scroll_manager.anchor(),
 5361            visible_rows: self.visible_line_count(),
 5362            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5363        }
 5364    }
 5365
 5366    pub fn splice_inlays(
 5367        &self,
 5368        to_remove: &[InlayId],
 5369        to_insert: Vec<Inlay>,
 5370        cx: &mut Context<Self>,
 5371    ) {
 5372        self.display_map.update(cx, |display_map, cx| {
 5373            display_map.splice_inlays(to_remove, to_insert, cx)
 5374        });
 5375        cx.notify();
 5376    }
 5377
 5378    fn trigger_on_type_formatting(
 5379        &self,
 5380        input: String,
 5381        window: &mut Window,
 5382        cx: &mut Context<Self>,
 5383    ) -> Option<Task<Result<()>>> {
 5384        if input.len() != 1 {
 5385            return None;
 5386        }
 5387
 5388        let project = self.project()?;
 5389        let position = self.selections.newest_anchor().head();
 5390        let (buffer, buffer_position) = self
 5391            .buffer
 5392            .read(cx)
 5393            .text_anchor_for_position(position, cx)?;
 5394
 5395        let settings = language_settings::language_settings(
 5396            buffer
 5397                .read(cx)
 5398                .language_at(buffer_position)
 5399                .map(|l| l.name()),
 5400            buffer.read(cx).file(),
 5401            cx,
 5402        );
 5403        if !settings.use_on_type_format {
 5404            return None;
 5405        }
 5406
 5407        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5408        // hence we do LSP request & edit on host side only — add formats to host's history.
 5409        let push_to_lsp_host_history = true;
 5410        // If this is not the host, append its history with new edits.
 5411        let push_to_client_history = project.read(cx).is_via_collab();
 5412
 5413        let on_type_formatting = project.update(cx, |project, cx| {
 5414            project.on_type_format(
 5415                buffer.clone(),
 5416                buffer_position,
 5417                input,
 5418                push_to_lsp_host_history,
 5419                cx,
 5420            )
 5421        });
 5422        Some(cx.spawn_in(window, async move |editor, cx| {
 5423            if let Some(transaction) = on_type_formatting.await? {
 5424                if push_to_client_history {
 5425                    buffer
 5426                        .update(cx, |buffer, _| {
 5427                            buffer.push_transaction(transaction, Instant::now());
 5428                            buffer.finalize_last_transaction();
 5429                        })
 5430                        .ok();
 5431                }
 5432                editor.update(cx, |editor, cx| {
 5433                    editor.refresh_document_highlights(cx);
 5434                })?;
 5435            }
 5436            Ok(())
 5437        }))
 5438    }
 5439
 5440    pub fn show_word_completions(
 5441        &mut self,
 5442        _: &ShowWordCompletions,
 5443        window: &mut Window,
 5444        cx: &mut Context<Self>,
 5445    ) {
 5446        self.open_or_update_completions_menu(
 5447            Some(CompletionsMenuSource::Words {
 5448                ignore_threshold: true,
 5449            }),
 5450            None,
 5451            window,
 5452            cx,
 5453        );
 5454    }
 5455
 5456    pub fn show_completions(
 5457        &mut self,
 5458        options: &ShowCompletions,
 5459        window: &mut Window,
 5460        cx: &mut Context<Self>,
 5461    ) {
 5462        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5463    }
 5464
 5465    fn open_or_update_completions_menu(
 5466        &mut self,
 5467        requested_source: Option<CompletionsMenuSource>,
 5468        trigger: Option<&str>,
 5469        window: &mut Window,
 5470        cx: &mut Context<Self>,
 5471    ) {
 5472        if self.pending_rename.is_some() {
 5473            return;
 5474        }
 5475
 5476        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5477
 5478        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5479        // inserted and selected. To handle that case, the start of the selection is used so that
 5480        // the menu starts with all choices.
 5481        let position = self
 5482            .selections
 5483            .newest_anchor()
 5484            .start
 5485            .bias_right(&multibuffer_snapshot);
 5486        if position.diff_base_anchor.is_some() {
 5487            return;
 5488        }
 5489        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5490        let Some(buffer) = buffer_position
 5491            .buffer_id
 5492            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5493        else {
 5494            return;
 5495        };
 5496        let buffer_snapshot = buffer.read(cx).snapshot();
 5497
 5498        let query: Option<Arc<String>> =
 5499            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5500                .map(|query| query.into());
 5501
 5502        drop(multibuffer_snapshot);
 5503
 5504        // Hide the current completions menu when query is empty. Without this, cached
 5505        // completions from before the trigger char may be reused (#32774).
 5506        if query.is_none() {
 5507            let menu_is_open = matches!(
 5508                self.context_menu.borrow().as_ref(),
 5509                Some(CodeContextMenu::Completions(_))
 5510            );
 5511            if menu_is_open {
 5512                self.hide_context_menu(window, cx);
 5513            }
 5514        }
 5515
 5516        let mut ignore_word_threshold = false;
 5517        let provider = match requested_source {
 5518            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5519            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5520                ignore_word_threshold = ignore_threshold;
 5521                None
 5522            }
 5523            Some(CompletionsMenuSource::SnippetChoices) => {
 5524                log::error!("bug: SnippetChoices requested_source is not handled");
 5525                None
 5526            }
 5527        };
 5528
 5529        let sort_completions = provider
 5530            .as_ref()
 5531            .is_some_and(|provider| provider.sort_completions());
 5532
 5533        let filter_completions = provider
 5534            .as_ref()
 5535            .is_none_or(|provider| provider.filter_completions());
 5536
 5537        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5538            if filter_completions {
 5539                menu.filter(query.clone(), provider.clone(), window, cx);
 5540            }
 5541            // When `is_incomplete` is false, no need to re-query completions when the current query
 5542            // is a suffix of the initial query.
 5543            if !menu.is_incomplete {
 5544                // If the new query is a suffix of the old query (typing more characters) and
 5545                // the previous result was complete, the existing completions can be filtered.
 5546                //
 5547                // Note that this is always true for snippet completions.
 5548                let query_matches = match (&menu.initial_query, &query) {
 5549                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5550                    (None, _) => true,
 5551                    _ => false,
 5552                };
 5553                if query_matches {
 5554                    let position_matches = if menu.initial_position == position {
 5555                        true
 5556                    } else {
 5557                        let snapshot = self.buffer.read(cx).read(cx);
 5558                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5559                    };
 5560                    if position_matches {
 5561                        return;
 5562                    }
 5563                }
 5564            }
 5565        };
 5566
 5567        let trigger_kind = match trigger {
 5568            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5569                CompletionTriggerKind::TRIGGER_CHARACTER
 5570            }
 5571            _ => CompletionTriggerKind::INVOKED,
 5572        };
 5573        let completion_context = CompletionContext {
 5574            trigger_character: trigger.and_then(|trigger| {
 5575                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5576                    Some(String::from(trigger))
 5577                } else {
 5578                    None
 5579                }
 5580            }),
 5581            trigger_kind,
 5582        };
 5583
 5584        let Anchor {
 5585            excerpt_id: buffer_excerpt_id,
 5586            text_anchor: buffer_position,
 5587            ..
 5588        } = buffer_position;
 5589
 5590        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5591            buffer_snapshot.surrounding_word(buffer_position, None)
 5592        {
 5593            let word_to_exclude = buffer_snapshot
 5594                .text_for_range(word_range.clone())
 5595                .collect::<String>();
 5596            (
 5597                buffer_snapshot.anchor_before(word_range.start)
 5598                    ..buffer_snapshot.anchor_after(buffer_position),
 5599                Some(word_to_exclude),
 5600            )
 5601        } else {
 5602            (buffer_position..buffer_position, None)
 5603        };
 5604
 5605        let language = buffer_snapshot
 5606            .language_at(buffer_position)
 5607            .map(|language| language.name());
 5608
 5609        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5610            .completions
 5611            .clone();
 5612
 5613        let show_completion_documentation = buffer_snapshot
 5614            .settings_at(buffer_position, cx)
 5615            .show_completion_documentation;
 5616
 5617        // The document can be large, so stay in reasonable bounds when searching for words,
 5618        // otherwise completion pop-up might be slow to appear.
 5619        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5620        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5621        let min_word_search = buffer_snapshot.clip_point(
 5622            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5623            Bias::Left,
 5624        );
 5625        let max_word_search = buffer_snapshot.clip_point(
 5626            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5627            Bias::Right,
 5628        );
 5629        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5630            ..buffer_snapshot.point_to_offset(max_word_search);
 5631
 5632        let skip_digits = query
 5633            .as_ref()
 5634            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5635
 5636        let omit_word_completions = !self.word_completions_enabled
 5637            || (!ignore_word_threshold
 5638                && match &query {
 5639                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5640                    None => completion_settings.words_min_length != 0,
 5641                });
 5642
 5643        let (mut words, provider_responses) = match &provider {
 5644            Some(provider) => {
 5645                let provider_responses = provider.completions(
 5646                    buffer_excerpt_id,
 5647                    &buffer,
 5648                    buffer_position,
 5649                    completion_context,
 5650                    window,
 5651                    cx,
 5652                );
 5653
 5654                let words = match (omit_word_completions, completion_settings.words) {
 5655                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5656                        Task::ready(BTreeMap::default())
 5657                    }
 5658                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5659                        .background_spawn(async move {
 5660                            buffer_snapshot.words_in_range(WordsQuery {
 5661                                fuzzy_contents: None,
 5662                                range: word_search_range,
 5663                                skip_digits,
 5664                            })
 5665                        }),
 5666                };
 5667
 5668                (words, provider_responses)
 5669            }
 5670            None => {
 5671                let words = if omit_word_completions {
 5672                    Task::ready(BTreeMap::default())
 5673                } else {
 5674                    cx.background_spawn(async move {
 5675                        buffer_snapshot.words_in_range(WordsQuery {
 5676                            fuzzy_contents: None,
 5677                            range: word_search_range,
 5678                            skip_digits,
 5679                        })
 5680                    })
 5681                };
 5682                (words, Task::ready(Ok(Vec::new())))
 5683            }
 5684        };
 5685
 5686        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5687
 5688        let id = post_inc(&mut self.next_completion_id);
 5689        let task = cx.spawn_in(window, async move |editor, cx| {
 5690            let Ok(()) = editor.update(cx, |this, _| {
 5691                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5692            }) else {
 5693                return;
 5694            };
 5695
 5696            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5697            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5698            let mut completions = Vec::new();
 5699            let mut is_incomplete = false;
 5700            let mut display_options: Option<CompletionDisplayOptions> = None;
 5701            if let Some(provider_responses) = provider_responses.await.log_err()
 5702                && !provider_responses.is_empty()
 5703            {
 5704                for response in provider_responses {
 5705                    completions.extend(response.completions);
 5706                    is_incomplete = is_incomplete || response.is_incomplete;
 5707                    match display_options.as_mut() {
 5708                        None => {
 5709                            display_options = Some(response.display_options);
 5710                        }
 5711                        Some(options) => options.merge(&response.display_options),
 5712                    }
 5713                }
 5714                if completion_settings.words == WordsCompletionMode::Fallback {
 5715                    words = Task::ready(BTreeMap::default());
 5716                }
 5717            }
 5718            let display_options = display_options.unwrap_or_default();
 5719
 5720            let mut words = words.await;
 5721            if let Some(word_to_exclude) = &word_to_exclude {
 5722                words.remove(word_to_exclude);
 5723            }
 5724            for lsp_completion in &completions {
 5725                words.remove(&lsp_completion.new_text);
 5726            }
 5727            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5728                replace_range: word_replace_range.clone(),
 5729                new_text: word.clone(),
 5730                label: CodeLabel::plain(word, None),
 5731                icon_path: None,
 5732                documentation: None,
 5733                source: CompletionSource::BufferWord {
 5734                    word_range,
 5735                    resolved: false,
 5736                },
 5737                insert_text_mode: Some(InsertTextMode::AS_IS),
 5738                confirm: None,
 5739            }));
 5740
 5741            let menu = if completions.is_empty() {
 5742                None
 5743            } else {
 5744                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5745                    let languages = editor
 5746                        .workspace
 5747                        .as_ref()
 5748                        .and_then(|(workspace, _)| workspace.upgrade())
 5749                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5750                    let menu = CompletionsMenu::new(
 5751                        id,
 5752                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5753                        sort_completions,
 5754                        show_completion_documentation,
 5755                        position,
 5756                        query.clone(),
 5757                        is_incomplete,
 5758                        buffer.clone(),
 5759                        completions.into(),
 5760                        display_options,
 5761                        snippet_sort_order,
 5762                        languages,
 5763                        language,
 5764                        cx,
 5765                    );
 5766
 5767                    let query = if filter_completions { query } else { None };
 5768                    let matches_task = if let Some(query) = query {
 5769                        menu.do_async_filtering(query, cx)
 5770                    } else {
 5771                        Task::ready(menu.unfiltered_matches())
 5772                    };
 5773                    (menu, matches_task)
 5774                }) else {
 5775                    return;
 5776                };
 5777
 5778                let matches = matches_task.await;
 5779
 5780                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5781                    // Newer menu already set, so exit.
 5782                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5783                        editor.context_menu.borrow().as_ref()
 5784                        && prev_menu.id > id
 5785                    {
 5786                        return;
 5787                    };
 5788
 5789                    // Only valid to take prev_menu because it the new menu is immediately set
 5790                    // below, or the menu is hidden.
 5791                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5792                        editor.context_menu.borrow_mut().take()
 5793                    {
 5794                        let position_matches =
 5795                            if prev_menu.initial_position == menu.initial_position {
 5796                                true
 5797                            } else {
 5798                                let snapshot = editor.buffer.read(cx).read(cx);
 5799                                prev_menu.initial_position.to_offset(&snapshot)
 5800                                    == menu.initial_position.to_offset(&snapshot)
 5801                            };
 5802                        if position_matches {
 5803                            // Preserve markdown cache before `set_filter_results` because it will
 5804                            // try to populate the documentation cache.
 5805                            menu.preserve_markdown_cache(prev_menu);
 5806                        }
 5807                    };
 5808
 5809                    menu.set_filter_results(matches, provider, window, cx);
 5810                }) else {
 5811                    return;
 5812                };
 5813
 5814                menu.visible().then_some(menu)
 5815            };
 5816
 5817            editor
 5818                .update_in(cx, |editor, window, cx| {
 5819                    if editor.focus_handle.is_focused(window)
 5820                        && let Some(menu) = menu
 5821                    {
 5822                        *editor.context_menu.borrow_mut() =
 5823                            Some(CodeContextMenu::Completions(menu));
 5824
 5825                        crate::hover_popover::hide_hover(editor, cx);
 5826                        if editor.show_edit_predictions_in_menu() {
 5827                            editor.update_visible_edit_prediction(window, cx);
 5828                        } else {
 5829                            editor.discard_edit_prediction(false, cx);
 5830                        }
 5831
 5832                        cx.notify();
 5833                        return;
 5834                    }
 5835
 5836                    if editor.completion_tasks.len() <= 1 {
 5837                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5838                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5839                        // If it was already hidden and we don't show edit predictions in the menu,
 5840                        // we should also show the edit prediction when available.
 5841                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5842                            editor.update_visible_edit_prediction(window, cx);
 5843                        }
 5844                    }
 5845                })
 5846                .ok();
 5847        });
 5848
 5849        self.completion_tasks.push((id, task));
 5850    }
 5851
 5852    #[cfg(feature = "test-support")]
 5853    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5854        let menu = self.context_menu.borrow();
 5855        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5856            let completions = menu.completions.borrow();
 5857            Some(completions.to_vec())
 5858        } else {
 5859            None
 5860        }
 5861    }
 5862
 5863    pub fn with_completions_menu_matching_id<R>(
 5864        &self,
 5865        id: CompletionId,
 5866        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5867    ) -> R {
 5868        let mut context_menu = self.context_menu.borrow_mut();
 5869        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5870            return f(None);
 5871        };
 5872        if completions_menu.id != id {
 5873            return f(None);
 5874        }
 5875        f(Some(completions_menu))
 5876    }
 5877
 5878    pub fn confirm_completion(
 5879        &mut self,
 5880        action: &ConfirmCompletion,
 5881        window: &mut Window,
 5882        cx: &mut Context<Self>,
 5883    ) -> Option<Task<Result<()>>> {
 5884        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5885        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5886    }
 5887
 5888    pub fn confirm_completion_insert(
 5889        &mut self,
 5890        _: &ConfirmCompletionInsert,
 5891        window: &mut Window,
 5892        cx: &mut Context<Self>,
 5893    ) -> Option<Task<Result<()>>> {
 5894        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5895        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5896    }
 5897
 5898    pub fn confirm_completion_replace(
 5899        &mut self,
 5900        _: &ConfirmCompletionReplace,
 5901        window: &mut Window,
 5902        cx: &mut Context<Self>,
 5903    ) -> Option<Task<Result<()>>> {
 5904        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5905        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5906    }
 5907
 5908    pub fn compose_completion(
 5909        &mut self,
 5910        action: &ComposeCompletion,
 5911        window: &mut Window,
 5912        cx: &mut Context<Self>,
 5913    ) -> Option<Task<Result<()>>> {
 5914        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5915        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5916    }
 5917
 5918    fn do_completion(
 5919        &mut self,
 5920        item_ix: Option<usize>,
 5921        intent: CompletionIntent,
 5922        window: &mut Window,
 5923        cx: &mut Context<Editor>,
 5924    ) -> Option<Task<Result<()>>> {
 5925        use language::ToOffset as _;
 5926
 5927        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5928        else {
 5929            return None;
 5930        };
 5931
 5932        let candidate_id = {
 5933            let entries = completions_menu.entries.borrow();
 5934            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5935            if self.show_edit_predictions_in_menu() {
 5936                self.discard_edit_prediction(true, cx);
 5937            }
 5938            mat.candidate_id
 5939        };
 5940
 5941        let completion = completions_menu
 5942            .completions
 5943            .borrow()
 5944            .get(candidate_id)?
 5945            .clone();
 5946        cx.stop_propagation();
 5947
 5948        let buffer_handle = completions_menu.buffer.clone();
 5949
 5950        let CompletionEdit {
 5951            new_text,
 5952            snippet,
 5953            replace_range,
 5954        } = process_completion_for_edit(
 5955            &completion,
 5956            intent,
 5957            &buffer_handle,
 5958            &completions_menu.initial_position.text_anchor,
 5959            cx,
 5960        );
 5961
 5962        let buffer = buffer_handle.read(cx);
 5963        let snapshot = self.buffer.read(cx).snapshot(cx);
 5964        let newest_anchor = self.selections.newest_anchor();
 5965        let replace_range_multibuffer = {
 5966            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5967            let multibuffer_anchor = snapshot
 5968                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5969                .unwrap()
 5970                ..snapshot
 5971                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5972                    .unwrap();
 5973            multibuffer_anchor.start.to_offset(&snapshot)
 5974                ..multibuffer_anchor.end.to_offset(&snapshot)
 5975        };
 5976        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5977            return None;
 5978        }
 5979
 5980        let old_text = buffer
 5981            .text_for_range(replace_range.clone())
 5982            .collect::<String>();
 5983        let lookbehind = newest_anchor
 5984            .start
 5985            .text_anchor
 5986            .to_offset(buffer)
 5987            .saturating_sub(replace_range.start);
 5988        let lookahead = replace_range
 5989            .end
 5990            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5991        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5992        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5993
 5994        let selections = self.selections.all::<usize>(cx);
 5995        let mut ranges = Vec::new();
 5996        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5997
 5998        for selection in &selections {
 5999            let range = if selection.id == newest_anchor.id {
 6000                replace_range_multibuffer.clone()
 6001            } else {
 6002                let mut range = selection.range();
 6003
 6004                // if prefix is present, don't duplicate it
 6005                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6006                    range.start = range.start.saturating_sub(lookbehind);
 6007
 6008                    // if suffix is also present, mimic the newest cursor and replace it
 6009                    if selection.id != newest_anchor.id
 6010                        && snapshot.contains_str_at(range.end, suffix)
 6011                    {
 6012                        range.end += lookahead;
 6013                    }
 6014                }
 6015                range
 6016            };
 6017
 6018            ranges.push(range.clone());
 6019
 6020            if !self.linked_edit_ranges.is_empty() {
 6021                let start_anchor = snapshot.anchor_before(range.start);
 6022                let end_anchor = snapshot.anchor_after(range.end);
 6023                if let Some(ranges) = self
 6024                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6025                {
 6026                    for (buffer, edits) in ranges {
 6027                        linked_edits
 6028                            .entry(buffer.clone())
 6029                            .or_default()
 6030                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6031                    }
 6032                }
 6033            }
 6034        }
 6035
 6036        let common_prefix_len = old_text
 6037            .chars()
 6038            .zip(new_text.chars())
 6039            .take_while(|(a, b)| a == b)
 6040            .map(|(a, _)| a.len_utf8())
 6041            .sum::<usize>();
 6042
 6043        cx.emit(EditorEvent::InputHandled {
 6044            utf16_range_to_replace: None,
 6045            text: new_text[common_prefix_len..].into(),
 6046        });
 6047
 6048        self.transact(window, cx, |editor, window, cx| {
 6049            if let Some(mut snippet) = snippet {
 6050                snippet.text = new_text.to_string();
 6051                editor
 6052                    .insert_snippet(&ranges, snippet, window, cx)
 6053                    .log_err();
 6054            } else {
 6055                editor.buffer.update(cx, |multi_buffer, cx| {
 6056                    let auto_indent = match completion.insert_text_mode {
 6057                        Some(InsertTextMode::AS_IS) => None,
 6058                        _ => editor.autoindent_mode.clone(),
 6059                    };
 6060                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6061                    multi_buffer.edit(edits, auto_indent, cx);
 6062                });
 6063            }
 6064            for (buffer, edits) in linked_edits {
 6065                buffer.update(cx, |buffer, cx| {
 6066                    let snapshot = buffer.snapshot();
 6067                    let edits = edits
 6068                        .into_iter()
 6069                        .map(|(range, text)| {
 6070                            use text::ToPoint as TP;
 6071                            let end_point = TP::to_point(&range.end, &snapshot);
 6072                            let start_point = TP::to_point(&range.start, &snapshot);
 6073                            (start_point..end_point, text)
 6074                        })
 6075                        .sorted_by_key(|(range, _)| range.start);
 6076                    buffer.edit(edits, None, cx);
 6077                })
 6078            }
 6079
 6080            editor.refresh_edit_prediction(true, false, window, cx);
 6081        });
 6082        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6083
 6084        let show_new_completions_on_confirm = completion
 6085            .confirm
 6086            .as_ref()
 6087            .is_some_and(|confirm| confirm(intent, window, cx));
 6088        if show_new_completions_on_confirm {
 6089            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6090        }
 6091
 6092        let provider = self.completion_provider.as_ref()?;
 6093        drop(completion);
 6094        let apply_edits = provider.apply_additional_edits_for_completion(
 6095            buffer_handle,
 6096            completions_menu.completions.clone(),
 6097            candidate_id,
 6098            true,
 6099            cx,
 6100        );
 6101
 6102        let editor_settings = EditorSettings::get_global(cx);
 6103        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6104            // After the code completion is finished, users often want to know what signatures are needed.
 6105            // so we should automatically call signature_help
 6106            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6107        }
 6108
 6109        Some(cx.foreground_executor().spawn(async move {
 6110            apply_edits.await?;
 6111            Ok(())
 6112        }))
 6113    }
 6114
 6115    pub fn toggle_code_actions(
 6116        &mut self,
 6117        action: &ToggleCodeActions,
 6118        window: &mut Window,
 6119        cx: &mut Context<Self>,
 6120    ) {
 6121        let quick_launch = action.quick_launch;
 6122        let mut context_menu = self.context_menu.borrow_mut();
 6123        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6124            if code_actions.deployed_from == action.deployed_from {
 6125                // Toggle if we're selecting the same one
 6126                *context_menu = None;
 6127                cx.notify();
 6128                return;
 6129            } else {
 6130                // Otherwise, clear it and start a new one
 6131                *context_menu = None;
 6132                cx.notify();
 6133            }
 6134        }
 6135        drop(context_menu);
 6136        let snapshot = self.snapshot(window, cx);
 6137        let deployed_from = action.deployed_from.clone();
 6138        let action = action.clone();
 6139        self.completion_tasks.clear();
 6140        self.discard_edit_prediction(false, cx);
 6141
 6142        let multibuffer_point = match &action.deployed_from {
 6143            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6144                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6145            }
 6146            _ => self.selections.newest::<Point>(cx).head(),
 6147        };
 6148        let Some((buffer, buffer_row)) = snapshot
 6149            .buffer_snapshot
 6150            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6151            .and_then(|(buffer_snapshot, range)| {
 6152                self.buffer()
 6153                    .read(cx)
 6154                    .buffer(buffer_snapshot.remote_id())
 6155                    .map(|buffer| (buffer, range.start.row))
 6156            })
 6157        else {
 6158            return;
 6159        };
 6160        let buffer_id = buffer.read(cx).remote_id();
 6161        let tasks = self
 6162            .tasks
 6163            .get(&(buffer_id, buffer_row))
 6164            .map(|t| Arc::new(t.to_owned()));
 6165
 6166        if !self.focus_handle.is_focused(window) {
 6167            return;
 6168        }
 6169        let project = self.project.clone();
 6170
 6171        let code_actions_task = match deployed_from {
 6172            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6173            _ => self.code_actions(buffer_row, window, cx),
 6174        };
 6175
 6176        let runnable_task = match deployed_from {
 6177            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6178            _ => {
 6179                let mut task_context_task = Task::ready(None);
 6180                if let Some(tasks) = &tasks
 6181                    && let Some(project) = project
 6182                {
 6183                    task_context_task =
 6184                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6185                }
 6186
 6187                cx.spawn_in(window, {
 6188                    let buffer = buffer.clone();
 6189                    async move |editor, cx| {
 6190                        let task_context = task_context_task.await;
 6191
 6192                        let resolved_tasks =
 6193                            tasks
 6194                                .zip(task_context.clone())
 6195                                .map(|(tasks, task_context)| ResolvedTasks {
 6196                                    templates: tasks.resolve(&task_context).collect(),
 6197                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6198                                        multibuffer_point.row,
 6199                                        tasks.column,
 6200                                    )),
 6201                                });
 6202                        let debug_scenarios = editor
 6203                            .update(cx, |editor, cx| {
 6204                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6205                            })?
 6206                            .await;
 6207                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6208                    }
 6209                })
 6210            }
 6211        };
 6212
 6213        cx.spawn_in(window, async move |editor, cx| {
 6214            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6215            let code_actions = code_actions_task.await;
 6216            let spawn_straight_away = quick_launch
 6217                && resolved_tasks
 6218                    .as_ref()
 6219                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6220                && code_actions
 6221                    .as_ref()
 6222                    .is_none_or(|actions| actions.is_empty())
 6223                && debug_scenarios.is_empty();
 6224
 6225            editor.update_in(cx, |editor, window, cx| {
 6226                crate::hover_popover::hide_hover(editor, cx);
 6227                let actions = CodeActionContents::new(
 6228                    resolved_tasks,
 6229                    code_actions,
 6230                    debug_scenarios,
 6231                    task_context.unwrap_or_default(),
 6232                );
 6233
 6234                // Don't show the menu if there are no actions available
 6235                if actions.is_empty() {
 6236                    cx.notify();
 6237                    return Task::ready(Ok(()));
 6238                }
 6239
 6240                *editor.context_menu.borrow_mut() =
 6241                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6242                        buffer,
 6243                        actions,
 6244                        selected_item: Default::default(),
 6245                        scroll_handle: UniformListScrollHandle::default(),
 6246                        deployed_from,
 6247                    }));
 6248                cx.notify();
 6249                if spawn_straight_away
 6250                    && let Some(task) = editor.confirm_code_action(
 6251                        &ConfirmCodeAction { item_ix: Some(0) },
 6252                        window,
 6253                        cx,
 6254                    )
 6255                {
 6256                    return task;
 6257                }
 6258
 6259                Task::ready(Ok(()))
 6260            })
 6261        })
 6262        .detach_and_log_err(cx);
 6263    }
 6264
 6265    fn debug_scenarios(
 6266        &mut self,
 6267        resolved_tasks: &Option<ResolvedTasks>,
 6268        buffer: &Entity<Buffer>,
 6269        cx: &mut App,
 6270    ) -> Task<Vec<task::DebugScenario>> {
 6271        maybe!({
 6272            let project = self.project()?;
 6273            let dap_store = project.read(cx).dap_store();
 6274            let mut scenarios = vec![];
 6275            let resolved_tasks = resolved_tasks.as_ref()?;
 6276            let buffer = buffer.read(cx);
 6277            let language = buffer.language()?;
 6278            let file = buffer.file();
 6279            let debug_adapter = language_settings(language.name().into(), file, cx)
 6280                .debuggers
 6281                .first()
 6282                .map(SharedString::from)
 6283                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6284
 6285            dap_store.update(cx, |dap_store, cx| {
 6286                for (_, task) in &resolved_tasks.templates {
 6287                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6288                        task.original_task().clone(),
 6289                        debug_adapter.clone().into(),
 6290                        task.display_label().to_owned().into(),
 6291                        cx,
 6292                    );
 6293                    scenarios.push(maybe_scenario);
 6294                }
 6295            });
 6296            Some(cx.background_spawn(async move {
 6297                futures::future::join_all(scenarios)
 6298                    .await
 6299                    .into_iter()
 6300                    .flatten()
 6301                    .collect::<Vec<_>>()
 6302            }))
 6303        })
 6304        .unwrap_or_else(|| Task::ready(vec![]))
 6305    }
 6306
 6307    fn code_actions(
 6308        &mut self,
 6309        buffer_row: u32,
 6310        window: &mut Window,
 6311        cx: &mut Context<Self>,
 6312    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6313        let mut task = self.code_actions_task.take();
 6314        cx.spawn_in(window, async move |editor, cx| {
 6315            while let Some(prev_task) = task {
 6316                prev_task.await.log_err();
 6317                task = editor
 6318                    .update(cx, |this, _| this.code_actions_task.take())
 6319                    .ok()?;
 6320            }
 6321
 6322            editor
 6323                .update(cx, |editor, cx| {
 6324                    editor
 6325                        .available_code_actions
 6326                        .clone()
 6327                        .and_then(|(location, code_actions)| {
 6328                            let snapshot = location.buffer.read(cx).snapshot();
 6329                            let point_range = location.range.to_point(&snapshot);
 6330                            let point_range = point_range.start.row..=point_range.end.row;
 6331                            if point_range.contains(&buffer_row) {
 6332                                Some(code_actions)
 6333                            } else {
 6334                                None
 6335                            }
 6336                        })
 6337                })
 6338                .ok()
 6339                .flatten()
 6340        })
 6341    }
 6342
 6343    pub fn confirm_code_action(
 6344        &mut self,
 6345        action: &ConfirmCodeAction,
 6346        window: &mut Window,
 6347        cx: &mut Context<Self>,
 6348    ) -> Option<Task<Result<()>>> {
 6349        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6350
 6351        let actions_menu =
 6352            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6353                menu
 6354            } else {
 6355                return None;
 6356            };
 6357
 6358        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6359        let action = actions_menu.actions.get(action_ix)?;
 6360        let title = action.label();
 6361        let buffer = actions_menu.buffer;
 6362        let workspace = self.workspace()?;
 6363
 6364        match action {
 6365            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6366                workspace.update(cx, |workspace, cx| {
 6367                    workspace.schedule_resolved_task(
 6368                        task_source_kind,
 6369                        resolved_task,
 6370                        false,
 6371                        window,
 6372                        cx,
 6373                    );
 6374
 6375                    Some(Task::ready(Ok(())))
 6376                })
 6377            }
 6378            CodeActionsItem::CodeAction {
 6379                excerpt_id,
 6380                action,
 6381                provider,
 6382            } => {
 6383                let apply_code_action =
 6384                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6385                let workspace = workspace.downgrade();
 6386                Some(cx.spawn_in(window, async move |editor, cx| {
 6387                    let project_transaction = apply_code_action.await?;
 6388                    Self::open_project_transaction(
 6389                        &editor,
 6390                        workspace,
 6391                        project_transaction,
 6392                        title,
 6393                        cx,
 6394                    )
 6395                    .await
 6396                }))
 6397            }
 6398            CodeActionsItem::DebugScenario(scenario) => {
 6399                let context = actions_menu.actions.context;
 6400
 6401                workspace.update(cx, |workspace, cx| {
 6402                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6403                    workspace.start_debug_session(
 6404                        scenario,
 6405                        context,
 6406                        Some(buffer),
 6407                        None,
 6408                        window,
 6409                        cx,
 6410                    );
 6411                });
 6412                Some(Task::ready(Ok(())))
 6413            }
 6414        }
 6415    }
 6416
 6417    pub async fn open_project_transaction(
 6418        editor: &WeakEntity<Editor>,
 6419        workspace: WeakEntity<Workspace>,
 6420        transaction: ProjectTransaction,
 6421        title: String,
 6422        cx: &mut AsyncWindowContext,
 6423    ) -> Result<()> {
 6424        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6425        cx.update(|_, cx| {
 6426            entries.sort_unstable_by_key(|(buffer, _)| {
 6427                buffer.read(cx).file().map(|f| f.path().clone())
 6428            });
 6429        })?;
 6430
 6431        // If the project transaction's edits are all contained within this editor, then
 6432        // avoid opening a new editor to display them.
 6433
 6434        if let Some((buffer, transaction)) = entries.first() {
 6435            if entries.len() == 1 {
 6436                let excerpt = editor.update(cx, |editor, cx| {
 6437                    editor
 6438                        .buffer()
 6439                        .read(cx)
 6440                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6441                })?;
 6442                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6443                    && excerpted_buffer == *buffer
 6444                {
 6445                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6446                        let excerpt_range = excerpt_range.to_offset(buffer);
 6447                        buffer
 6448                            .edited_ranges_for_transaction::<usize>(transaction)
 6449                            .all(|range| {
 6450                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6451                            })
 6452                    })?;
 6453
 6454                    if all_edits_within_excerpt {
 6455                        return Ok(());
 6456                    }
 6457                }
 6458            }
 6459        } else {
 6460            return Ok(());
 6461        }
 6462
 6463        let mut ranges_to_highlight = Vec::new();
 6464        let excerpt_buffer = cx.new(|cx| {
 6465            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6466            for (buffer_handle, transaction) in &entries {
 6467                let edited_ranges = buffer_handle
 6468                    .read(cx)
 6469                    .edited_ranges_for_transaction::<Point>(transaction)
 6470                    .collect::<Vec<_>>();
 6471                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6472                    PathKey::for_buffer(buffer_handle, cx),
 6473                    buffer_handle.clone(),
 6474                    edited_ranges,
 6475                    multibuffer_context_lines(cx),
 6476                    cx,
 6477                );
 6478
 6479                ranges_to_highlight.extend(ranges);
 6480            }
 6481            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6482            multibuffer
 6483        })?;
 6484
 6485        workspace.update_in(cx, |workspace, window, cx| {
 6486            let project = workspace.project().clone();
 6487            let editor =
 6488                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6489            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6490            editor.update(cx, |editor, cx| {
 6491                editor.highlight_background::<Self>(
 6492                    &ranges_to_highlight,
 6493                    |theme| theme.colors().editor_highlighted_line_background,
 6494                    cx,
 6495                );
 6496            });
 6497        })?;
 6498
 6499        Ok(())
 6500    }
 6501
 6502    pub fn clear_code_action_providers(&mut self) {
 6503        self.code_action_providers.clear();
 6504        self.available_code_actions.take();
 6505    }
 6506
 6507    pub fn add_code_action_provider(
 6508        &mut self,
 6509        provider: Rc<dyn CodeActionProvider>,
 6510        window: &mut Window,
 6511        cx: &mut Context<Self>,
 6512    ) {
 6513        if self
 6514            .code_action_providers
 6515            .iter()
 6516            .any(|existing_provider| existing_provider.id() == provider.id())
 6517        {
 6518            return;
 6519        }
 6520
 6521        self.code_action_providers.push(provider);
 6522        self.refresh_code_actions(window, cx);
 6523    }
 6524
 6525    pub fn remove_code_action_provider(
 6526        &mut self,
 6527        id: Arc<str>,
 6528        window: &mut Window,
 6529        cx: &mut Context<Self>,
 6530    ) {
 6531        self.code_action_providers
 6532            .retain(|provider| provider.id() != id);
 6533        self.refresh_code_actions(window, cx);
 6534    }
 6535
 6536    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6537        !self.code_action_providers.is_empty()
 6538            && EditorSettings::get_global(cx).toolbar.code_actions
 6539    }
 6540
 6541    pub fn has_available_code_actions(&self) -> bool {
 6542        self.available_code_actions
 6543            .as_ref()
 6544            .is_some_and(|(_, actions)| !actions.is_empty())
 6545    }
 6546
 6547    fn render_inline_code_actions(
 6548        &self,
 6549        icon_size: ui::IconSize,
 6550        display_row: DisplayRow,
 6551        is_active: bool,
 6552        cx: &mut Context<Self>,
 6553    ) -> AnyElement {
 6554        let show_tooltip = !self.context_menu_visible();
 6555        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6556            .icon_size(icon_size)
 6557            .shape(ui::IconButtonShape::Square)
 6558            .icon_color(ui::Color::Hidden)
 6559            .toggle_state(is_active)
 6560            .when(show_tooltip, |this| {
 6561                this.tooltip({
 6562                    let focus_handle = self.focus_handle.clone();
 6563                    move |window, cx| {
 6564                        Tooltip::for_action_in(
 6565                            "Toggle Code Actions",
 6566                            &ToggleCodeActions {
 6567                                deployed_from: None,
 6568                                quick_launch: false,
 6569                            },
 6570                            &focus_handle,
 6571                            window,
 6572                            cx,
 6573                        )
 6574                    }
 6575                })
 6576            })
 6577            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6578                window.focus(&editor.focus_handle(cx));
 6579                editor.toggle_code_actions(
 6580                    &crate::actions::ToggleCodeActions {
 6581                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6582                            display_row,
 6583                        )),
 6584                        quick_launch: false,
 6585                    },
 6586                    window,
 6587                    cx,
 6588                );
 6589            }))
 6590            .into_any_element()
 6591    }
 6592
 6593    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6594        &self.context_menu
 6595    }
 6596
 6597    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6598        let newest_selection = self.selections.newest_anchor().clone();
 6599        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6600        let buffer = self.buffer.read(cx);
 6601        if newest_selection.head().diff_base_anchor.is_some() {
 6602            return None;
 6603        }
 6604        let (start_buffer, start) =
 6605            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6606        let (end_buffer, end) =
 6607            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6608        if start_buffer != end_buffer {
 6609            return None;
 6610        }
 6611
 6612        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6613            cx.background_executor()
 6614                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6615                .await;
 6616
 6617            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6618                let providers = this.code_action_providers.clone();
 6619                let tasks = this
 6620                    .code_action_providers
 6621                    .iter()
 6622                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6623                    .collect::<Vec<_>>();
 6624                (providers, tasks)
 6625            })?;
 6626
 6627            let mut actions = Vec::new();
 6628            for (provider, provider_actions) in
 6629                providers.into_iter().zip(future::join_all(tasks).await)
 6630            {
 6631                if let Some(provider_actions) = provider_actions.log_err() {
 6632                    actions.extend(provider_actions.into_iter().map(|action| {
 6633                        AvailableCodeAction {
 6634                            excerpt_id: newest_selection.start.excerpt_id,
 6635                            action,
 6636                            provider: provider.clone(),
 6637                        }
 6638                    }));
 6639                }
 6640            }
 6641
 6642            this.update(cx, |this, cx| {
 6643                this.available_code_actions = if actions.is_empty() {
 6644                    None
 6645                } else {
 6646                    Some((
 6647                        Location {
 6648                            buffer: start_buffer,
 6649                            range: start..end,
 6650                        },
 6651                        actions.into(),
 6652                    ))
 6653                };
 6654                cx.notify();
 6655            })
 6656        }));
 6657        None
 6658    }
 6659
 6660    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6661        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6662            self.show_git_blame_inline = false;
 6663
 6664            self.show_git_blame_inline_delay_task =
 6665                Some(cx.spawn_in(window, async move |this, cx| {
 6666                    cx.background_executor().timer(delay).await;
 6667
 6668                    this.update(cx, |this, cx| {
 6669                        this.show_git_blame_inline = true;
 6670                        cx.notify();
 6671                    })
 6672                    .log_err();
 6673                }));
 6674        }
 6675    }
 6676
 6677    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6678        let snapshot = self.snapshot(window, cx);
 6679        let cursor = self.selections.newest::<Point>(cx).head();
 6680        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6681        else {
 6682            return;
 6683        };
 6684
 6685        let Some(blame) = self.blame.as_ref() else {
 6686            return;
 6687        };
 6688
 6689        let row_info = RowInfo {
 6690            buffer_id: Some(buffer.remote_id()),
 6691            buffer_row: Some(point.row),
 6692            ..Default::default()
 6693        };
 6694        let Some((buffer, blame_entry)) = blame
 6695            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6696            .flatten()
 6697        else {
 6698            return;
 6699        };
 6700
 6701        let anchor = self.selections.newest_anchor().head();
 6702        let position = self.to_pixel_point(anchor, &snapshot, window);
 6703        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6704            self.show_blame_popover(
 6705                buffer,
 6706                &blame_entry,
 6707                position + last_bounds.origin,
 6708                true,
 6709                cx,
 6710            );
 6711        };
 6712    }
 6713
 6714    fn show_blame_popover(
 6715        &mut self,
 6716        buffer: BufferId,
 6717        blame_entry: &BlameEntry,
 6718        position: gpui::Point<Pixels>,
 6719        ignore_timeout: bool,
 6720        cx: &mut Context<Self>,
 6721    ) {
 6722        if let Some(state) = &mut self.inline_blame_popover {
 6723            state.hide_task.take();
 6724        } else {
 6725            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6726            let blame_entry = blame_entry.clone();
 6727            let show_task = cx.spawn(async move |editor, cx| {
 6728                if !ignore_timeout {
 6729                    cx.background_executor()
 6730                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6731                        .await;
 6732                }
 6733                editor
 6734                    .update(cx, |editor, cx| {
 6735                        editor.inline_blame_popover_show_task.take();
 6736                        let Some(blame) = editor.blame.as_ref() else {
 6737                            return;
 6738                        };
 6739                        let blame = blame.read(cx);
 6740                        let details = blame.details_for_entry(buffer, &blame_entry);
 6741                        let markdown = cx.new(|cx| {
 6742                            Markdown::new(
 6743                                details
 6744                                    .as_ref()
 6745                                    .map(|message| message.message.clone())
 6746                                    .unwrap_or_default(),
 6747                                None,
 6748                                None,
 6749                                cx,
 6750                            )
 6751                        });
 6752                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6753                            position,
 6754                            hide_task: None,
 6755                            popover_bounds: None,
 6756                            popover_state: InlineBlamePopoverState {
 6757                                scroll_handle: ScrollHandle::new(),
 6758                                commit_message: details,
 6759                                markdown,
 6760                            },
 6761                            keyboard_grace: ignore_timeout,
 6762                        });
 6763                        cx.notify();
 6764                    })
 6765                    .ok();
 6766            });
 6767            self.inline_blame_popover_show_task = Some(show_task);
 6768        }
 6769    }
 6770
 6771    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6772        self.inline_blame_popover_show_task.take();
 6773        if let Some(state) = &mut self.inline_blame_popover {
 6774            let hide_task = cx.spawn(async move |editor, cx| {
 6775                cx.background_executor()
 6776                    .timer(std::time::Duration::from_millis(100))
 6777                    .await;
 6778                editor
 6779                    .update(cx, |editor, cx| {
 6780                        editor.inline_blame_popover.take();
 6781                        cx.notify();
 6782                    })
 6783                    .ok();
 6784            });
 6785            state.hide_task = Some(hide_task);
 6786        }
 6787    }
 6788
 6789    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6790        if self.pending_rename.is_some() {
 6791            return None;
 6792        }
 6793
 6794        let provider = self.semantics_provider.clone()?;
 6795        let buffer = self.buffer.read(cx);
 6796        let newest_selection = self.selections.newest_anchor().clone();
 6797        let cursor_position = newest_selection.head();
 6798        let (cursor_buffer, cursor_buffer_position) =
 6799            buffer.text_anchor_for_position(cursor_position, cx)?;
 6800        let (tail_buffer, tail_buffer_position) =
 6801            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6802        if cursor_buffer != tail_buffer {
 6803            return None;
 6804        }
 6805
 6806        let snapshot = cursor_buffer.read(cx).snapshot();
 6807        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6808        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6809        if start_word_range != end_word_range {
 6810            self.document_highlights_task.take();
 6811            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6812            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6813            return None;
 6814        }
 6815
 6816        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6817        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6818            cx.background_executor()
 6819                .timer(Duration::from_millis(debounce))
 6820                .await;
 6821
 6822            let highlights = if let Some(highlights) = cx
 6823                .update(|cx| {
 6824                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6825                })
 6826                .ok()
 6827                .flatten()
 6828            {
 6829                highlights.await.log_err()
 6830            } else {
 6831                None
 6832            };
 6833
 6834            if let Some(highlights) = highlights {
 6835                this.update(cx, |this, cx| {
 6836                    if this.pending_rename.is_some() {
 6837                        return;
 6838                    }
 6839
 6840                    let buffer = this.buffer.read(cx);
 6841                    if buffer
 6842                        .text_anchor_for_position(cursor_position, cx)
 6843                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6844                    {
 6845                        return;
 6846                    }
 6847
 6848                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6849                    let mut write_ranges = Vec::new();
 6850                    let mut read_ranges = Vec::new();
 6851                    for highlight in highlights {
 6852                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6853                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6854                        {
 6855                            let start = highlight
 6856                                .range
 6857                                .start
 6858                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6859                            let end = highlight
 6860                                .range
 6861                                .end
 6862                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6863                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6864                                continue;
 6865                            }
 6866
 6867                            let range = Anchor {
 6868                                buffer_id: Some(buffer_id),
 6869                                excerpt_id,
 6870                                text_anchor: start,
 6871                                diff_base_anchor: None,
 6872                            }..Anchor {
 6873                                buffer_id: Some(buffer_id),
 6874                                excerpt_id,
 6875                                text_anchor: end,
 6876                                diff_base_anchor: None,
 6877                            };
 6878                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6879                                write_ranges.push(range);
 6880                            } else {
 6881                                read_ranges.push(range);
 6882                            }
 6883                        }
 6884                    }
 6885
 6886                    this.highlight_background::<DocumentHighlightRead>(
 6887                        &read_ranges,
 6888                        |theme| theme.colors().editor_document_highlight_read_background,
 6889                        cx,
 6890                    );
 6891                    this.highlight_background::<DocumentHighlightWrite>(
 6892                        &write_ranges,
 6893                        |theme| theme.colors().editor_document_highlight_write_background,
 6894                        cx,
 6895                    );
 6896                    cx.notify();
 6897                })
 6898                .log_err();
 6899            }
 6900        }));
 6901        None
 6902    }
 6903
 6904    fn prepare_highlight_query_from_selection(
 6905        &mut self,
 6906        cx: &mut Context<Editor>,
 6907    ) -> Option<(String, Range<Anchor>)> {
 6908        if matches!(self.mode, EditorMode::SingleLine) {
 6909            return None;
 6910        }
 6911        if !EditorSettings::get_global(cx).selection_highlight {
 6912            return None;
 6913        }
 6914        if self.selections.count() != 1 || self.selections.line_mode() {
 6915            return None;
 6916        }
 6917        let selection = self.selections.newest::<Point>(cx);
 6918        if selection.is_empty() || selection.start.row != selection.end.row {
 6919            return None;
 6920        }
 6921        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6922        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6923        let query = multi_buffer_snapshot
 6924            .text_for_range(selection_anchor_range.clone())
 6925            .collect::<String>();
 6926        if query.trim().is_empty() {
 6927            return None;
 6928        }
 6929        Some((query, selection_anchor_range))
 6930    }
 6931
 6932    fn update_selection_occurrence_highlights(
 6933        &mut self,
 6934        query_text: String,
 6935        query_range: Range<Anchor>,
 6936        multi_buffer_range_to_query: Range<Point>,
 6937        use_debounce: bool,
 6938        window: &mut Window,
 6939        cx: &mut Context<Editor>,
 6940    ) -> Task<()> {
 6941        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6942        cx.spawn_in(window, async move |editor, cx| {
 6943            if use_debounce {
 6944                cx.background_executor()
 6945                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6946                    .await;
 6947            }
 6948            let match_task = cx.background_spawn(async move {
 6949                let buffer_ranges = multi_buffer_snapshot
 6950                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6951                    .into_iter()
 6952                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6953                let mut match_ranges = Vec::new();
 6954                let Ok(regex) = project::search::SearchQuery::text(
 6955                    query_text.clone(),
 6956                    false,
 6957                    false,
 6958                    false,
 6959                    Default::default(),
 6960                    Default::default(),
 6961                    false,
 6962                    None,
 6963                ) else {
 6964                    return Vec::default();
 6965                };
 6966                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6967                    match_ranges.extend(
 6968                        regex
 6969                            .search(buffer_snapshot, Some(search_range.clone()))
 6970                            .await
 6971                            .into_iter()
 6972                            .filter_map(|match_range| {
 6973                                let match_start = buffer_snapshot
 6974                                    .anchor_after(search_range.start + match_range.start);
 6975                                let match_end = buffer_snapshot
 6976                                    .anchor_before(search_range.start + match_range.end);
 6977                                let match_anchor_range = Anchor::range_in_buffer(
 6978                                    excerpt_id,
 6979                                    buffer_snapshot.remote_id(),
 6980                                    match_start..match_end,
 6981                                );
 6982                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6983                            }),
 6984                    );
 6985                }
 6986                match_ranges
 6987            });
 6988            let match_ranges = match_task.await;
 6989            editor
 6990                .update_in(cx, |editor, _, cx| {
 6991                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6992                    if !match_ranges.is_empty() {
 6993                        editor.highlight_background::<SelectedTextHighlight>(
 6994                            &match_ranges,
 6995                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6996                            cx,
 6997                        )
 6998                    }
 6999                })
 7000                .log_err();
 7001        })
 7002    }
 7003
 7004    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7005        struct NewlineFold;
 7006        let type_id = std::any::TypeId::of::<NewlineFold>();
 7007        if !self.mode.is_single_line() {
 7008            return;
 7009        }
 7010        let snapshot = self.snapshot(window, cx);
 7011        if snapshot.buffer_snapshot.max_point().row == 0 {
 7012            return;
 7013        }
 7014        let task = cx.background_spawn(async move {
 7015            let new_newlines = snapshot
 7016                .buffer_chars_at(0)
 7017                .filter_map(|(c, i)| {
 7018                    if c == '\n' {
 7019                        Some(
 7020                            snapshot.buffer_snapshot.anchor_after(i)
 7021                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7022                        )
 7023                    } else {
 7024                        None
 7025                    }
 7026                })
 7027                .collect::<Vec<_>>();
 7028            let existing_newlines = snapshot
 7029                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7030                .filter_map(|fold| {
 7031                    if fold.placeholder.type_tag == Some(type_id) {
 7032                        Some(fold.range.start..fold.range.end)
 7033                    } else {
 7034                        None
 7035                    }
 7036                })
 7037                .collect::<Vec<_>>();
 7038
 7039            (new_newlines, existing_newlines)
 7040        });
 7041        self.folding_newlines = cx.spawn(async move |this, cx| {
 7042            let (new_newlines, existing_newlines) = task.await;
 7043            if new_newlines == existing_newlines {
 7044                return;
 7045            }
 7046            let placeholder = FoldPlaceholder {
 7047                render: Arc::new(move |_, _, cx| {
 7048                    div()
 7049                        .bg(cx.theme().status().hint_background)
 7050                        .border_b_1()
 7051                        .size_full()
 7052                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7053                        .border_color(cx.theme().status().hint)
 7054                        .child("\\n")
 7055                        .into_any()
 7056                }),
 7057                constrain_width: false,
 7058                merge_adjacent: false,
 7059                type_tag: Some(type_id),
 7060            };
 7061            let creases = new_newlines
 7062                .into_iter()
 7063                .map(|range| Crease::simple(range, placeholder.clone()))
 7064                .collect();
 7065            this.update(cx, |this, cx| {
 7066                this.display_map.update(cx, |display_map, cx| {
 7067                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7068                    display_map.fold(creases, cx);
 7069                });
 7070            })
 7071            .ok();
 7072        });
 7073    }
 7074
 7075    fn refresh_selected_text_highlights(
 7076        &mut self,
 7077        on_buffer_edit: bool,
 7078        window: &mut Window,
 7079        cx: &mut Context<Editor>,
 7080    ) {
 7081        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7082        else {
 7083            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7084            self.quick_selection_highlight_task.take();
 7085            self.debounced_selection_highlight_task.take();
 7086            return;
 7087        };
 7088        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7089        if on_buffer_edit
 7090            || self
 7091                .quick_selection_highlight_task
 7092                .as_ref()
 7093                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7094        {
 7095            let multi_buffer_visible_start = self
 7096                .scroll_manager
 7097                .anchor()
 7098                .anchor
 7099                .to_point(&multi_buffer_snapshot);
 7100            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7101                multi_buffer_visible_start
 7102                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7103                Bias::Left,
 7104            );
 7105            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7106            self.quick_selection_highlight_task = Some((
 7107                query_range.clone(),
 7108                self.update_selection_occurrence_highlights(
 7109                    query_text.clone(),
 7110                    query_range.clone(),
 7111                    multi_buffer_visible_range,
 7112                    false,
 7113                    window,
 7114                    cx,
 7115                ),
 7116            ));
 7117        }
 7118        if on_buffer_edit
 7119            || self
 7120                .debounced_selection_highlight_task
 7121                .as_ref()
 7122                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7123        {
 7124            let multi_buffer_start = multi_buffer_snapshot
 7125                .anchor_before(0)
 7126                .to_point(&multi_buffer_snapshot);
 7127            let multi_buffer_end = multi_buffer_snapshot
 7128                .anchor_after(multi_buffer_snapshot.len())
 7129                .to_point(&multi_buffer_snapshot);
 7130            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7131            self.debounced_selection_highlight_task = Some((
 7132                query_range.clone(),
 7133                self.update_selection_occurrence_highlights(
 7134                    query_text,
 7135                    query_range,
 7136                    multi_buffer_full_range,
 7137                    true,
 7138                    window,
 7139                    cx,
 7140                ),
 7141            ));
 7142        }
 7143    }
 7144
 7145    pub fn refresh_edit_prediction(
 7146        &mut self,
 7147        debounce: bool,
 7148        user_requested: bool,
 7149        window: &mut Window,
 7150        cx: &mut Context<Self>,
 7151    ) -> Option<()> {
 7152        if DisableAiSettings::get_global(cx).disable_ai {
 7153            return None;
 7154        }
 7155
 7156        let provider = self.edit_prediction_provider()?;
 7157        let cursor = self.selections.newest_anchor().head();
 7158        let (buffer, cursor_buffer_position) =
 7159            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7160
 7161        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7162            self.discard_edit_prediction(false, cx);
 7163            return None;
 7164        }
 7165
 7166        self.update_visible_edit_prediction(window, cx);
 7167
 7168        if !user_requested
 7169            && (!self.should_show_edit_predictions()
 7170                || !self.is_focused(window)
 7171                || buffer.read(cx).is_empty())
 7172        {
 7173            self.discard_edit_prediction(false, cx);
 7174            return None;
 7175        }
 7176
 7177        provider.refresh(
 7178            self.project.clone(),
 7179            buffer,
 7180            cursor_buffer_position,
 7181            debounce,
 7182            cx,
 7183        );
 7184        Some(())
 7185    }
 7186
 7187    fn show_edit_predictions_in_menu(&self) -> bool {
 7188        match self.edit_prediction_settings {
 7189            EditPredictionSettings::Disabled => false,
 7190            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7191        }
 7192    }
 7193
 7194    pub fn edit_predictions_enabled(&self) -> bool {
 7195        match self.edit_prediction_settings {
 7196            EditPredictionSettings::Disabled => false,
 7197            EditPredictionSettings::Enabled { .. } => true,
 7198        }
 7199    }
 7200
 7201    fn edit_prediction_requires_modifier(&self) -> bool {
 7202        match self.edit_prediction_settings {
 7203            EditPredictionSettings::Disabled => false,
 7204            EditPredictionSettings::Enabled {
 7205                preview_requires_modifier,
 7206                ..
 7207            } => preview_requires_modifier,
 7208        }
 7209    }
 7210
 7211    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7212        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7213            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7214            self.discard_edit_prediction(false, cx);
 7215        } else {
 7216            let selection = self.selections.newest_anchor();
 7217            let cursor = selection.head();
 7218
 7219            if let Some((buffer, cursor_buffer_position)) =
 7220                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7221            {
 7222                self.edit_prediction_settings =
 7223                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7224            }
 7225        }
 7226    }
 7227
 7228    fn edit_prediction_settings_at_position(
 7229        &self,
 7230        buffer: &Entity<Buffer>,
 7231        buffer_position: language::Anchor,
 7232        cx: &App,
 7233    ) -> EditPredictionSettings {
 7234        if !self.mode.is_full()
 7235            || !self.show_edit_predictions_override.unwrap_or(true)
 7236            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7237        {
 7238            return EditPredictionSettings::Disabled;
 7239        }
 7240
 7241        let buffer = buffer.read(cx);
 7242
 7243        let file = buffer.file();
 7244
 7245        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7246            return EditPredictionSettings::Disabled;
 7247        };
 7248
 7249        let by_provider = matches!(
 7250            self.menu_edit_predictions_policy,
 7251            MenuEditPredictionsPolicy::ByProvider
 7252        );
 7253
 7254        let show_in_menu = by_provider
 7255            && self
 7256                .edit_prediction_provider
 7257                .as_ref()
 7258                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7259
 7260        let preview_requires_modifier =
 7261            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7262
 7263        EditPredictionSettings::Enabled {
 7264            show_in_menu,
 7265            preview_requires_modifier,
 7266        }
 7267    }
 7268
 7269    fn should_show_edit_predictions(&self) -> bool {
 7270        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7271    }
 7272
 7273    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7274        matches!(
 7275            self.edit_prediction_preview,
 7276            EditPredictionPreview::Active { .. }
 7277        )
 7278    }
 7279
 7280    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7281        let cursor = self.selections.newest_anchor().head();
 7282        if let Some((buffer, cursor_position)) =
 7283            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7284        {
 7285            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7286        } else {
 7287            false
 7288        }
 7289    }
 7290
 7291    pub fn supports_minimap(&self, cx: &App) -> bool {
 7292        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7293    }
 7294
 7295    fn edit_predictions_enabled_in_buffer(
 7296        &self,
 7297        buffer: &Entity<Buffer>,
 7298        buffer_position: language::Anchor,
 7299        cx: &App,
 7300    ) -> bool {
 7301        maybe!({
 7302            if self.read_only(cx) {
 7303                return Some(false);
 7304            }
 7305            let provider = self.edit_prediction_provider()?;
 7306            if !provider.is_enabled(buffer, buffer_position, cx) {
 7307                return Some(false);
 7308            }
 7309            let buffer = buffer.read(cx);
 7310            let Some(file) = buffer.file() else {
 7311                return Some(true);
 7312            };
 7313            let settings = all_language_settings(Some(file), cx);
 7314            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7315        })
 7316        .unwrap_or(false)
 7317    }
 7318
 7319    fn cycle_edit_prediction(
 7320        &mut self,
 7321        direction: Direction,
 7322        window: &mut Window,
 7323        cx: &mut Context<Self>,
 7324    ) -> Option<()> {
 7325        let provider = self.edit_prediction_provider()?;
 7326        let cursor = self.selections.newest_anchor().head();
 7327        let (buffer, cursor_buffer_position) =
 7328            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7329        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7330            return None;
 7331        }
 7332
 7333        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7334        self.update_visible_edit_prediction(window, cx);
 7335
 7336        Some(())
 7337    }
 7338
 7339    pub fn show_edit_prediction(
 7340        &mut self,
 7341        _: &ShowEditPrediction,
 7342        window: &mut Window,
 7343        cx: &mut Context<Self>,
 7344    ) {
 7345        if !self.has_active_edit_prediction() {
 7346            self.refresh_edit_prediction(false, true, window, cx);
 7347            return;
 7348        }
 7349
 7350        self.update_visible_edit_prediction(window, cx);
 7351    }
 7352
 7353    pub fn display_cursor_names(
 7354        &mut self,
 7355        _: &DisplayCursorNames,
 7356        window: &mut Window,
 7357        cx: &mut Context<Self>,
 7358    ) {
 7359        self.show_cursor_names(window, cx);
 7360    }
 7361
 7362    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7363        self.show_cursor_names = true;
 7364        cx.notify();
 7365        cx.spawn_in(window, async move |this, cx| {
 7366            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7367            this.update(cx, |this, cx| {
 7368                this.show_cursor_names = false;
 7369                cx.notify()
 7370            })
 7371            .ok()
 7372        })
 7373        .detach();
 7374    }
 7375
 7376    pub fn next_edit_prediction(
 7377        &mut self,
 7378        _: &NextEditPrediction,
 7379        window: &mut Window,
 7380        cx: &mut Context<Self>,
 7381    ) {
 7382        if self.has_active_edit_prediction() {
 7383            self.cycle_edit_prediction(Direction::Next, window, cx);
 7384        } else {
 7385            let is_copilot_disabled = self
 7386                .refresh_edit_prediction(false, true, window, cx)
 7387                .is_none();
 7388            if is_copilot_disabled {
 7389                cx.propagate();
 7390            }
 7391        }
 7392    }
 7393
 7394    pub fn previous_edit_prediction(
 7395        &mut self,
 7396        _: &PreviousEditPrediction,
 7397        window: &mut Window,
 7398        cx: &mut Context<Self>,
 7399    ) {
 7400        if self.has_active_edit_prediction() {
 7401            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7402        } else {
 7403            let is_copilot_disabled = self
 7404                .refresh_edit_prediction(false, true, window, cx)
 7405                .is_none();
 7406            if is_copilot_disabled {
 7407                cx.propagate();
 7408            }
 7409        }
 7410    }
 7411
 7412    pub fn accept_edit_prediction(
 7413        &mut self,
 7414        _: &AcceptEditPrediction,
 7415        window: &mut Window,
 7416        cx: &mut Context<Self>,
 7417    ) {
 7418        if self.show_edit_predictions_in_menu() {
 7419            self.hide_context_menu(window, cx);
 7420        }
 7421
 7422        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7423            return;
 7424        };
 7425
 7426        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7427
 7428        match &active_edit_prediction.completion {
 7429            EditPrediction::Move { target, .. } => {
 7430                let target = *target;
 7431
 7432                if let Some(position_map) = &self.last_position_map {
 7433                    if position_map
 7434                        .visible_row_range
 7435                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7436                        || !self.edit_prediction_requires_modifier()
 7437                    {
 7438                        self.unfold_ranges(&[target..target], true, false, cx);
 7439                        // Note that this is also done in vim's handler of the Tab action.
 7440                        self.change_selections(
 7441                            SelectionEffects::scroll(Autoscroll::newest()),
 7442                            window,
 7443                            cx,
 7444                            |selections| {
 7445                                selections.select_anchor_ranges([target..target]);
 7446                            },
 7447                        );
 7448                        self.clear_row_highlights::<EditPredictionPreview>();
 7449
 7450                        self.edit_prediction_preview
 7451                            .set_previous_scroll_position(None);
 7452                    } else {
 7453                        self.edit_prediction_preview
 7454                            .set_previous_scroll_position(Some(
 7455                                position_map.snapshot.scroll_anchor,
 7456                            ));
 7457
 7458                        self.highlight_rows::<EditPredictionPreview>(
 7459                            target..target,
 7460                            cx.theme().colors().editor_highlighted_line_background,
 7461                            RowHighlightOptions {
 7462                                autoscroll: true,
 7463                                ..Default::default()
 7464                            },
 7465                            cx,
 7466                        );
 7467                        self.request_autoscroll(Autoscroll::fit(), cx);
 7468                    }
 7469                }
 7470            }
 7471            EditPrediction::Edit { edits, .. } => {
 7472                if let Some(provider) = self.edit_prediction_provider() {
 7473                    provider.accept(cx);
 7474                }
 7475
 7476                // Store the transaction ID and selections before applying the edit
 7477                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7478
 7479                let snapshot = self.buffer.read(cx).snapshot(cx);
 7480                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7481
 7482                self.buffer.update(cx, |buffer, cx| {
 7483                    buffer.edit(edits.iter().cloned(), None, cx)
 7484                });
 7485
 7486                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7487                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7488                });
 7489
 7490                let selections = self.selections.disjoint_anchors_arc();
 7491                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7492                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7493                    if has_new_transaction {
 7494                        self.selection_history
 7495                            .insert_transaction(transaction_id_now, selections);
 7496                    }
 7497                }
 7498
 7499                self.update_visible_edit_prediction(window, cx);
 7500                if self.active_edit_prediction.is_none() {
 7501                    self.refresh_edit_prediction(true, true, window, cx);
 7502                }
 7503
 7504                cx.notify();
 7505            }
 7506        }
 7507
 7508        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7509    }
 7510
 7511    pub fn accept_partial_edit_prediction(
 7512        &mut self,
 7513        _: &AcceptPartialEditPrediction,
 7514        window: &mut Window,
 7515        cx: &mut Context<Self>,
 7516    ) {
 7517        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7518            return;
 7519        };
 7520        if self.selections.count() != 1 {
 7521            return;
 7522        }
 7523
 7524        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7525
 7526        match &active_edit_prediction.completion {
 7527            EditPrediction::Move { target, .. } => {
 7528                let target = *target;
 7529                self.change_selections(
 7530                    SelectionEffects::scroll(Autoscroll::newest()),
 7531                    window,
 7532                    cx,
 7533                    |selections| {
 7534                        selections.select_anchor_ranges([target..target]);
 7535                    },
 7536                );
 7537            }
 7538            EditPrediction::Edit { edits, .. } => {
 7539                // Find an insertion that starts at the cursor position.
 7540                let snapshot = self.buffer.read(cx).snapshot(cx);
 7541                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7542                let insertion = edits.iter().find_map(|(range, text)| {
 7543                    let range = range.to_offset(&snapshot);
 7544                    if range.is_empty() && range.start == cursor_offset {
 7545                        Some(text)
 7546                    } else {
 7547                        None
 7548                    }
 7549                });
 7550
 7551                if let Some(text) = insertion {
 7552                    let mut partial_completion = text
 7553                        .chars()
 7554                        .by_ref()
 7555                        .take_while(|c| c.is_alphabetic())
 7556                        .collect::<String>();
 7557                    if partial_completion.is_empty() {
 7558                        partial_completion = text
 7559                            .chars()
 7560                            .by_ref()
 7561                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7562                            .collect::<String>();
 7563                    }
 7564
 7565                    cx.emit(EditorEvent::InputHandled {
 7566                        utf16_range_to_replace: None,
 7567                        text: partial_completion.clone().into(),
 7568                    });
 7569
 7570                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7571
 7572                    self.refresh_edit_prediction(true, true, window, cx);
 7573                    cx.notify();
 7574                } else {
 7575                    self.accept_edit_prediction(&Default::default(), window, cx);
 7576                }
 7577            }
 7578        }
 7579    }
 7580
 7581    fn discard_edit_prediction(
 7582        &mut self,
 7583        should_report_edit_prediction_event: bool,
 7584        cx: &mut Context<Self>,
 7585    ) -> bool {
 7586        if should_report_edit_prediction_event {
 7587            let completion_id = self
 7588                .active_edit_prediction
 7589                .as_ref()
 7590                .and_then(|active_completion| active_completion.completion_id.clone());
 7591
 7592            self.report_edit_prediction_event(completion_id, false, cx);
 7593        }
 7594
 7595        if let Some(provider) = self.edit_prediction_provider() {
 7596            provider.discard(cx);
 7597        }
 7598
 7599        self.take_active_edit_prediction(cx)
 7600    }
 7601
 7602    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7603        let Some(provider) = self.edit_prediction_provider() else {
 7604            return;
 7605        };
 7606
 7607        let Some((_, buffer, _)) = self
 7608            .buffer
 7609            .read(cx)
 7610            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7611        else {
 7612            return;
 7613        };
 7614
 7615        let extension = buffer
 7616            .read(cx)
 7617            .file()
 7618            .and_then(|file| Some(file.path().extension()?.to_string()));
 7619
 7620        let event_type = match accepted {
 7621            true => "Edit Prediction Accepted",
 7622            false => "Edit Prediction Discarded",
 7623        };
 7624        telemetry::event!(
 7625            event_type,
 7626            provider = provider.name(),
 7627            prediction_id = id,
 7628            suggestion_accepted = accepted,
 7629            file_extension = extension,
 7630        );
 7631    }
 7632
 7633    pub fn has_active_edit_prediction(&self) -> bool {
 7634        self.active_edit_prediction.is_some()
 7635    }
 7636
 7637    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7638        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7639            return false;
 7640        };
 7641
 7642        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7643        self.clear_highlights::<EditPredictionHighlight>(cx);
 7644        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7645        true
 7646    }
 7647
 7648    /// Returns true when we're displaying the edit prediction popover below the cursor
 7649    /// like we are not previewing and the LSP autocomplete menu is visible
 7650    /// or we are in `when_holding_modifier` mode.
 7651    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7652        if self.edit_prediction_preview_is_active()
 7653            || !self.show_edit_predictions_in_menu()
 7654            || !self.edit_predictions_enabled()
 7655        {
 7656            return false;
 7657        }
 7658
 7659        if self.has_visible_completions_menu() {
 7660            return true;
 7661        }
 7662
 7663        has_completion && self.edit_prediction_requires_modifier()
 7664    }
 7665
 7666    fn handle_modifiers_changed(
 7667        &mut self,
 7668        modifiers: Modifiers,
 7669        position_map: &PositionMap,
 7670        window: &mut Window,
 7671        cx: &mut Context<Self>,
 7672    ) {
 7673        if self.show_edit_predictions_in_menu() {
 7674            self.update_edit_prediction_preview(&modifiers, window, cx);
 7675        }
 7676
 7677        self.update_selection_mode(&modifiers, position_map, window, cx);
 7678
 7679        let mouse_position = window.mouse_position();
 7680        if !position_map.text_hitbox.is_hovered(window) {
 7681            return;
 7682        }
 7683
 7684        self.update_hovered_link(
 7685            position_map.point_for_position(mouse_position),
 7686            &position_map.snapshot,
 7687            modifiers,
 7688            window,
 7689            cx,
 7690        )
 7691    }
 7692
 7693    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7694        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7695        if invert {
 7696            match multi_cursor_setting {
 7697                MultiCursorModifier::Alt => modifiers.alt,
 7698                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7699            }
 7700        } else {
 7701            match multi_cursor_setting {
 7702                MultiCursorModifier::Alt => modifiers.secondary(),
 7703                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7704            }
 7705        }
 7706    }
 7707
 7708    fn columnar_selection_mode(
 7709        modifiers: &Modifiers,
 7710        cx: &mut Context<Self>,
 7711    ) -> Option<ColumnarMode> {
 7712        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7713            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7714                Some(ColumnarMode::FromMouse)
 7715            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7716                Some(ColumnarMode::FromSelection)
 7717            } else {
 7718                None
 7719            }
 7720        } else {
 7721            None
 7722        }
 7723    }
 7724
 7725    fn update_selection_mode(
 7726        &mut self,
 7727        modifiers: &Modifiers,
 7728        position_map: &PositionMap,
 7729        window: &mut Window,
 7730        cx: &mut Context<Self>,
 7731    ) {
 7732        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7733            return;
 7734        };
 7735        if self.selections.pending_anchor().is_none() {
 7736            return;
 7737        }
 7738
 7739        let mouse_position = window.mouse_position();
 7740        let point_for_position = position_map.point_for_position(mouse_position);
 7741        let position = point_for_position.previous_valid;
 7742
 7743        self.select(
 7744            SelectPhase::BeginColumnar {
 7745                position,
 7746                reset: false,
 7747                mode,
 7748                goal_column: point_for_position.exact_unclipped.column(),
 7749            },
 7750            window,
 7751            cx,
 7752        );
 7753    }
 7754
 7755    fn update_edit_prediction_preview(
 7756        &mut self,
 7757        modifiers: &Modifiers,
 7758        window: &mut Window,
 7759        cx: &mut Context<Self>,
 7760    ) {
 7761        let mut modifiers_held = false;
 7762        if let Some(accept_keystroke) = self
 7763            .accept_edit_prediction_keybind(false, window, cx)
 7764            .keystroke()
 7765        {
 7766            modifiers_held = modifiers_held
 7767                || (accept_keystroke.modifiers() == modifiers
 7768                    && accept_keystroke.modifiers().modified());
 7769        };
 7770        if let Some(accept_partial_keystroke) = self
 7771            .accept_edit_prediction_keybind(true, window, cx)
 7772            .keystroke()
 7773        {
 7774            modifiers_held = modifiers_held
 7775                || (accept_partial_keystroke.modifiers() == modifiers
 7776                    && accept_partial_keystroke.modifiers().modified());
 7777        }
 7778
 7779        if modifiers_held {
 7780            if matches!(
 7781                self.edit_prediction_preview,
 7782                EditPredictionPreview::Inactive { .. }
 7783            ) {
 7784                self.edit_prediction_preview = EditPredictionPreview::Active {
 7785                    previous_scroll_position: None,
 7786                    since: Instant::now(),
 7787                };
 7788
 7789                self.update_visible_edit_prediction(window, cx);
 7790                cx.notify();
 7791            }
 7792        } else if let EditPredictionPreview::Active {
 7793            previous_scroll_position,
 7794            since,
 7795        } = self.edit_prediction_preview
 7796        {
 7797            if let (Some(previous_scroll_position), Some(position_map)) =
 7798                (previous_scroll_position, self.last_position_map.as_ref())
 7799            {
 7800                self.set_scroll_position(
 7801                    previous_scroll_position
 7802                        .scroll_position(&position_map.snapshot.display_snapshot),
 7803                    window,
 7804                    cx,
 7805                );
 7806            }
 7807
 7808            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7809                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7810            };
 7811            self.clear_row_highlights::<EditPredictionPreview>();
 7812            self.update_visible_edit_prediction(window, cx);
 7813            cx.notify();
 7814        }
 7815    }
 7816
 7817    fn update_visible_edit_prediction(
 7818        &mut self,
 7819        _window: &mut Window,
 7820        cx: &mut Context<Self>,
 7821    ) -> Option<()> {
 7822        if DisableAiSettings::get_global(cx).disable_ai {
 7823            return None;
 7824        }
 7825
 7826        if self.ime_transaction.is_some() {
 7827            self.discard_edit_prediction(false, cx);
 7828            return None;
 7829        }
 7830
 7831        let selection = self.selections.newest_anchor();
 7832        let cursor = selection.head();
 7833        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7834        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7835        let excerpt_id = cursor.excerpt_id;
 7836
 7837        let show_in_menu = self.show_edit_predictions_in_menu();
 7838        let completions_menu_has_precedence = !show_in_menu
 7839            && (self.context_menu.borrow().is_some()
 7840                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7841
 7842        if completions_menu_has_precedence
 7843            || !offset_selection.is_empty()
 7844            || self
 7845                .active_edit_prediction
 7846                .as_ref()
 7847                .is_some_and(|completion| {
 7848                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7849                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7850                    !invalidation_range.contains(&offset_selection.head())
 7851                })
 7852        {
 7853            self.discard_edit_prediction(false, cx);
 7854            return None;
 7855        }
 7856
 7857        self.take_active_edit_prediction(cx);
 7858        let Some(provider) = self.edit_prediction_provider() else {
 7859            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7860            return None;
 7861        };
 7862
 7863        let (buffer, cursor_buffer_position) =
 7864            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7865
 7866        self.edit_prediction_settings =
 7867            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7868
 7869        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7870
 7871        if self.edit_prediction_indent_conflict {
 7872            let cursor_point = cursor.to_point(&multibuffer);
 7873
 7874            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7875
 7876            if let Some((_, indent)) = indents.iter().next()
 7877                && indent.len == cursor_point.column
 7878            {
 7879                self.edit_prediction_indent_conflict = false;
 7880            }
 7881        }
 7882
 7883        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7884        let edits = edit_prediction
 7885            .edits
 7886            .into_iter()
 7887            .flat_map(|(range, new_text)| {
 7888                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7889                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7890                Some((start..end, new_text))
 7891            })
 7892            .collect::<Vec<_>>();
 7893        if edits.is_empty() {
 7894            return None;
 7895        }
 7896
 7897        let first_edit_start = edits.first().unwrap().0.start;
 7898        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7899        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7900
 7901        let last_edit_end = edits.last().unwrap().0.end;
 7902        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7903        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7904
 7905        let cursor_row = cursor.to_point(&multibuffer).row;
 7906
 7907        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7908
 7909        let mut inlay_ids = Vec::new();
 7910        let invalidation_row_range;
 7911        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7912            Some(cursor_row..edit_end_row)
 7913        } else if cursor_row > edit_end_row {
 7914            Some(edit_start_row..cursor_row)
 7915        } else {
 7916            None
 7917        };
 7918        let supports_jump = self
 7919            .edit_prediction_provider
 7920            .as_ref()
 7921            .map(|provider| provider.provider.supports_jump_to_edit())
 7922            .unwrap_or(true);
 7923
 7924        let is_move = supports_jump
 7925            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7926        let completion = if is_move {
 7927            invalidation_row_range =
 7928                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7929            let target = first_edit_start;
 7930            EditPrediction::Move { target, snapshot }
 7931        } else {
 7932            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7933                && !self.edit_predictions_hidden_for_vim_mode;
 7934
 7935            if show_completions_in_buffer {
 7936                if edits
 7937                    .iter()
 7938                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7939                {
 7940                    let mut inlays = Vec::new();
 7941                    for (range, new_text) in &edits {
 7942                        let inlay = Inlay::edit_prediction(
 7943                            post_inc(&mut self.next_inlay_id),
 7944                            range.start,
 7945                            new_text.as_str(),
 7946                        );
 7947                        inlay_ids.push(inlay.id);
 7948                        inlays.push(inlay);
 7949                    }
 7950
 7951                    self.splice_inlays(&[], inlays, cx);
 7952                } else {
 7953                    let background_color = cx.theme().status().deleted_background;
 7954                    self.highlight_text::<EditPredictionHighlight>(
 7955                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7956                        HighlightStyle {
 7957                            background_color: Some(background_color),
 7958                            ..Default::default()
 7959                        },
 7960                        cx,
 7961                    );
 7962                }
 7963            }
 7964
 7965            invalidation_row_range = edit_start_row..edit_end_row;
 7966
 7967            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7968                if provider.show_tab_accept_marker() {
 7969                    EditDisplayMode::TabAccept
 7970                } else {
 7971                    EditDisplayMode::Inline
 7972                }
 7973            } else {
 7974                EditDisplayMode::DiffPopover
 7975            };
 7976
 7977            EditPrediction::Edit {
 7978                edits,
 7979                edit_preview: edit_prediction.edit_preview,
 7980                display_mode,
 7981                snapshot,
 7982            }
 7983        };
 7984
 7985        let invalidation_range = multibuffer
 7986            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7987            ..multibuffer.anchor_after(Point::new(
 7988                invalidation_row_range.end,
 7989                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7990            ));
 7991
 7992        self.stale_edit_prediction_in_menu = None;
 7993        self.active_edit_prediction = Some(EditPredictionState {
 7994            inlay_ids,
 7995            completion,
 7996            completion_id: edit_prediction.id,
 7997            invalidation_range,
 7998        });
 7999
 8000        cx.notify();
 8001
 8002        Some(())
 8003    }
 8004
 8005    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8006        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8007    }
 8008
 8009    fn clear_tasks(&mut self) {
 8010        self.tasks.clear()
 8011    }
 8012
 8013    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8014        if self.tasks.insert(key, value).is_some() {
 8015            // This case should hopefully be rare, but just in case...
 8016            log::error!(
 8017                "multiple different run targets found on a single line, only the last target will be rendered"
 8018            )
 8019        }
 8020    }
 8021
 8022    /// Get all display points of breakpoints that will be rendered within editor
 8023    ///
 8024    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8025    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8026    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8027    fn active_breakpoints(
 8028        &self,
 8029        range: Range<DisplayRow>,
 8030        window: &mut Window,
 8031        cx: &mut Context<Self>,
 8032    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8033        let mut breakpoint_display_points = HashMap::default();
 8034
 8035        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8036            return breakpoint_display_points;
 8037        };
 8038
 8039        let snapshot = self.snapshot(window, cx);
 8040
 8041        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8042        let Some(project) = self.project() else {
 8043            return breakpoint_display_points;
 8044        };
 8045
 8046        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8047            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8048
 8049        for (buffer_snapshot, range, excerpt_id) in
 8050            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8051        {
 8052            let Some(buffer) = project
 8053                .read(cx)
 8054                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8055            else {
 8056                continue;
 8057            };
 8058            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8059                &buffer,
 8060                Some(
 8061                    buffer_snapshot.anchor_before(range.start)
 8062                        ..buffer_snapshot.anchor_after(range.end),
 8063                ),
 8064                buffer_snapshot,
 8065                cx,
 8066            );
 8067            for (breakpoint, state) in breakpoints {
 8068                let multi_buffer_anchor =
 8069                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8070                let position = multi_buffer_anchor
 8071                    .to_point(multi_buffer_snapshot)
 8072                    .to_display_point(&snapshot);
 8073
 8074                breakpoint_display_points.insert(
 8075                    position.row(),
 8076                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8077                );
 8078            }
 8079        }
 8080
 8081        breakpoint_display_points
 8082    }
 8083
 8084    fn breakpoint_context_menu(
 8085        &self,
 8086        anchor: Anchor,
 8087        window: &mut Window,
 8088        cx: &mut Context<Self>,
 8089    ) -> Entity<ui::ContextMenu> {
 8090        let weak_editor = cx.weak_entity();
 8091        let focus_handle = self.focus_handle(cx);
 8092
 8093        let row = self
 8094            .buffer
 8095            .read(cx)
 8096            .snapshot(cx)
 8097            .summary_for_anchor::<Point>(&anchor)
 8098            .row;
 8099
 8100        let breakpoint = self
 8101            .breakpoint_at_row(row, window, cx)
 8102            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8103
 8104        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8105            "Edit Log Breakpoint"
 8106        } else {
 8107            "Set Log Breakpoint"
 8108        };
 8109
 8110        let condition_breakpoint_msg = if breakpoint
 8111            .as_ref()
 8112            .is_some_and(|bp| bp.1.condition.is_some())
 8113        {
 8114            "Edit Condition Breakpoint"
 8115        } else {
 8116            "Set Condition Breakpoint"
 8117        };
 8118
 8119        let hit_condition_breakpoint_msg = if breakpoint
 8120            .as_ref()
 8121            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8122        {
 8123            "Edit Hit Condition Breakpoint"
 8124        } else {
 8125            "Set Hit Condition Breakpoint"
 8126        };
 8127
 8128        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8129            "Unset Breakpoint"
 8130        } else {
 8131            "Set Breakpoint"
 8132        };
 8133
 8134        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8135
 8136        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8137            BreakpointState::Enabled => Some("Disable"),
 8138            BreakpointState::Disabled => Some("Enable"),
 8139        });
 8140
 8141        let (anchor, breakpoint) =
 8142            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8143
 8144        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8145            menu.on_blur_subscription(Subscription::new(|| {}))
 8146                .context(focus_handle)
 8147                .when(run_to_cursor, |this| {
 8148                    let weak_editor = weak_editor.clone();
 8149                    this.entry("Run to cursor", None, move |window, cx| {
 8150                        weak_editor
 8151                            .update(cx, |editor, cx| {
 8152                                editor.change_selections(
 8153                                    SelectionEffects::no_scroll(),
 8154                                    window,
 8155                                    cx,
 8156                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8157                                );
 8158                            })
 8159                            .ok();
 8160
 8161                        window.dispatch_action(Box::new(RunToCursor), cx);
 8162                    })
 8163                    .separator()
 8164                })
 8165                .when_some(toggle_state_msg, |this, msg| {
 8166                    this.entry(msg, None, {
 8167                        let weak_editor = weak_editor.clone();
 8168                        let breakpoint = breakpoint.clone();
 8169                        move |_window, cx| {
 8170                            weak_editor
 8171                                .update(cx, |this, cx| {
 8172                                    this.edit_breakpoint_at_anchor(
 8173                                        anchor,
 8174                                        breakpoint.as_ref().clone(),
 8175                                        BreakpointEditAction::InvertState,
 8176                                        cx,
 8177                                    );
 8178                                })
 8179                                .log_err();
 8180                        }
 8181                    })
 8182                })
 8183                .entry(set_breakpoint_msg, None, {
 8184                    let weak_editor = weak_editor.clone();
 8185                    let breakpoint = breakpoint.clone();
 8186                    move |_window, cx| {
 8187                        weak_editor
 8188                            .update(cx, |this, cx| {
 8189                                this.edit_breakpoint_at_anchor(
 8190                                    anchor,
 8191                                    breakpoint.as_ref().clone(),
 8192                                    BreakpointEditAction::Toggle,
 8193                                    cx,
 8194                                );
 8195                            })
 8196                            .log_err();
 8197                    }
 8198                })
 8199                .entry(log_breakpoint_msg, None, {
 8200                    let breakpoint = breakpoint.clone();
 8201                    let weak_editor = weak_editor.clone();
 8202                    move |window, cx| {
 8203                        weak_editor
 8204                            .update(cx, |this, cx| {
 8205                                this.add_edit_breakpoint_block(
 8206                                    anchor,
 8207                                    breakpoint.as_ref(),
 8208                                    BreakpointPromptEditAction::Log,
 8209                                    window,
 8210                                    cx,
 8211                                );
 8212                            })
 8213                            .log_err();
 8214                    }
 8215                })
 8216                .entry(condition_breakpoint_msg, None, {
 8217                    let breakpoint = breakpoint.clone();
 8218                    let weak_editor = weak_editor.clone();
 8219                    move |window, cx| {
 8220                        weak_editor
 8221                            .update(cx, |this, cx| {
 8222                                this.add_edit_breakpoint_block(
 8223                                    anchor,
 8224                                    breakpoint.as_ref(),
 8225                                    BreakpointPromptEditAction::Condition,
 8226                                    window,
 8227                                    cx,
 8228                                );
 8229                            })
 8230                            .log_err();
 8231                    }
 8232                })
 8233                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8234                    weak_editor
 8235                        .update(cx, |this, cx| {
 8236                            this.add_edit_breakpoint_block(
 8237                                anchor,
 8238                                breakpoint.as_ref(),
 8239                                BreakpointPromptEditAction::HitCondition,
 8240                                window,
 8241                                cx,
 8242                            );
 8243                        })
 8244                        .log_err();
 8245                })
 8246        })
 8247    }
 8248
 8249    fn render_breakpoint(
 8250        &self,
 8251        position: Anchor,
 8252        row: DisplayRow,
 8253        breakpoint: &Breakpoint,
 8254        state: Option<BreakpointSessionState>,
 8255        cx: &mut Context<Self>,
 8256    ) -> IconButton {
 8257        let is_rejected = state.is_some_and(|s| !s.verified);
 8258        // Is it a breakpoint that shows up when hovering over gutter?
 8259        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8260            (false, false),
 8261            |PhantomBreakpointIndicator {
 8262                 is_active,
 8263                 display_row,
 8264                 collides_with_existing_breakpoint,
 8265             }| {
 8266                (
 8267                    is_active && display_row == row,
 8268                    collides_with_existing_breakpoint,
 8269                )
 8270            },
 8271        );
 8272
 8273        let (color, icon) = {
 8274            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8275                (false, false) => ui::IconName::DebugBreakpoint,
 8276                (true, false) => ui::IconName::DebugLogBreakpoint,
 8277                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8278                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8279            };
 8280
 8281            let color = if is_phantom {
 8282                Color::Hint
 8283            } else if is_rejected {
 8284                Color::Disabled
 8285            } else {
 8286                Color::Debugger
 8287            };
 8288
 8289            (color, icon)
 8290        };
 8291
 8292        let breakpoint = Arc::from(breakpoint.clone());
 8293
 8294        let alt_as_text = gpui::Keystroke {
 8295            modifiers: Modifiers::secondary_key(),
 8296            ..Default::default()
 8297        };
 8298        let primary_action_text = if breakpoint.is_disabled() {
 8299            "Enable breakpoint"
 8300        } else if is_phantom && !collides_with_existing {
 8301            "Set breakpoint"
 8302        } else {
 8303            "Unset breakpoint"
 8304        };
 8305        let focus_handle = self.focus_handle.clone();
 8306
 8307        let meta = if is_rejected {
 8308            SharedString::from("No executable code is associated with this line.")
 8309        } else if collides_with_existing && !breakpoint.is_disabled() {
 8310            SharedString::from(format!(
 8311                "{alt_as_text}-click to disable,\nright-click for more options."
 8312            ))
 8313        } else {
 8314            SharedString::from("Right-click for more options.")
 8315        };
 8316        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8317            .icon_size(IconSize::XSmall)
 8318            .size(ui::ButtonSize::None)
 8319            .when(is_rejected, |this| {
 8320                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8321            })
 8322            .icon_color(color)
 8323            .style(ButtonStyle::Transparent)
 8324            .on_click(cx.listener({
 8325                move |editor, event: &ClickEvent, window, cx| {
 8326                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8327                        BreakpointEditAction::InvertState
 8328                    } else {
 8329                        BreakpointEditAction::Toggle
 8330                    };
 8331
 8332                    window.focus(&editor.focus_handle(cx));
 8333                    editor.edit_breakpoint_at_anchor(
 8334                        position,
 8335                        breakpoint.as_ref().clone(),
 8336                        edit_action,
 8337                        cx,
 8338                    );
 8339                }
 8340            }))
 8341            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8342                editor.set_breakpoint_context_menu(
 8343                    row,
 8344                    Some(position),
 8345                    event.position(),
 8346                    window,
 8347                    cx,
 8348                );
 8349            }))
 8350            .tooltip(move |window, cx| {
 8351                Tooltip::with_meta_in(
 8352                    primary_action_text,
 8353                    Some(&ToggleBreakpoint),
 8354                    meta.clone(),
 8355                    &focus_handle,
 8356                    window,
 8357                    cx,
 8358                )
 8359            })
 8360    }
 8361
 8362    fn build_tasks_context(
 8363        project: &Entity<Project>,
 8364        buffer: &Entity<Buffer>,
 8365        buffer_row: u32,
 8366        tasks: &Arc<RunnableTasks>,
 8367        cx: &mut Context<Self>,
 8368    ) -> Task<Option<task::TaskContext>> {
 8369        let position = Point::new(buffer_row, tasks.column);
 8370        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8371        let location = Location {
 8372            buffer: buffer.clone(),
 8373            range: range_start..range_start,
 8374        };
 8375        // Fill in the environmental variables from the tree-sitter captures
 8376        let mut captured_task_variables = TaskVariables::default();
 8377        for (capture_name, value) in tasks.extra_variables.clone() {
 8378            captured_task_variables.insert(
 8379                task::VariableName::Custom(capture_name.into()),
 8380                value.clone(),
 8381            );
 8382        }
 8383        project.update(cx, |project, cx| {
 8384            project.task_store().update(cx, |task_store, cx| {
 8385                task_store.task_context_for_location(captured_task_variables, location, cx)
 8386            })
 8387        })
 8388    }
 8389
 8390    pub fn spawn_nearest_task(
 8391        &mut self,
 8392        action: &SpawnNearestTask,
 8393        window: &mut Window,
 8394        cx: &mut Context<Self>,
 8395    ) {
 8396        let Some((workspace, _)) = self.workspace.clone() else {
 8397            return;
 8398        };
 8399        let Some(project) = self.project.clone() else {
 8400            return;
 8401        };
 8402
 8403        // Try to find a closest, enclosing node using tree-sitter that has a task
 8404        let Some((buffer, buffer_row, tasks)) = self
 8405            .find_enclosing_node_task(cx)
 8406            // Or find the task that's closest in row-distance.
 8407            .or_else(|| self.find_closest_task(cx))
 8408        else {
 8409            return;
 8410        };
 8411
 8412        let reveal_strategy = action.reveal;
 8413        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8414        cx.spawn_in(window, async move |_, cx| {
 8415            let context = task_context.await?;
 8416            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8417
 8418            let resolved = &mut resolved_task.resolved;
 8419            resolved.reveal = reveal_strategy;
 8420
 8421            workspace
 8422                .update_in(cx, |workspace, window, cx| {
 8423                    workspace.schedule_resolved_task(
 8424                        task_source_kind,
 8425                        resolved_task,
 8426                        false,
 8427                        window,
 8428                        cx,
 8429                    );
 8430                })
 8431                .ok()
 8432        })
 8433        .detach();
 8434    }
 8435
 8436    fn find_closest_task(
 8437        &mut self,
 8438        cx: &mut Context<Self>,
 8439    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8440        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8441
 8442        let ((buffer_id, row), tasks) = self
 8443            .tasks
 8444            .iter()
 8445            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8446
 8447        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8448        let tasks = Arc::new(tasks.to_owned());
 8449        Some((buffer, *row, tasks))
 8450    }
 8451
 8452    fn find_enclosing_node_task(
 8453        &mut self,
 8454        cx: &mut Context<Self>,
 8455    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8456        let snapshot = self.buffer.read(cx).snapshot(cx);
 8457        let offset = self.selections.newest::<usize>(cx).head();
 8458        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8459        let buffer_id = excerpt.buffer().remote_id();
 8460
 8461        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8462        let mut cursor = layer.node().walk();
 8463
 8464        while cursor.goto_first_child_for_byte(offset).is_some() {
 8465            if cursor.node().end_byte() == offset {
 8466                cursor.goto_next_sibling();
 8467            }
 8468        }
 8469
 8470        // Ascend to the smallest ancestor that contains the range and has a task.
 8471        loop {
 8472            let node = cursor.node();
 8473            let node_range = node.byte_range();
 8474            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8475
 8476            // Check if this node contains our offset
 8477            if node_range.start <= offset && node_range.end >= offset {
 8478                // If it contains offset, check for task
 8479                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8480                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8481                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8482                }
 8483            }
 8484
 8485            if !cursor.goto_parent() {
 8486                break;
 8487            }
 8488        }
 8489        None
 8490    }
 8491
 8492    fn render_run_indicator(
 8493        &self,
 8494        _style: &EditorStyle,
 8495        is_active: bool,
 8496        row: DisplayRow,
 8497        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8498        cx: &mut Context<Self>,
 8499    ) -> IconButton {
 8500        let color = Color::Muted;
 8501        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8502
 8503        IconButton::new(
 8504            ("run_indicator", row.0 as usize),
 8505            ui::IconName::PlayOutlined,
 8506        )
 8507        .shape(ui::IconButtonShape::Square)
 8508        .icon_size(IconSize::XSmall)
 8509        .icon_color(color)
 8510        .toggle_state(is_active)
 8511        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8512            let quick_launch = match e {
 8513                ClickEvent::Keyboard(_) => true,
 8514                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8515            };
 8516
 8517            window.focus(&editor.focus_handle(cx));
 8518            editor.toggle_code_actions(
 8519                &ToggleCodeActions {
 8520                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8521                    quick_launch,
 8522                },
 8523                window,
 8524                cx,
 8525            );
 8526        }))
 8527        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8528            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8529        }))
 8530    }
 8531
 8532    pub fn context_menu_visible(&self) -> bool {
 8533        !self.edit_prediction_preview_is_active()
 8534            && self
 8535                .context_menu
 8536                .borrow()
 8537                .as_ref()
 8538                .is_some_and(|menu| menu.visible())
 8539    }
 8540
 8541    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8542        self.context_menu
 8543            .borrow()
 8544            .as_ref()
 8545            .map(|menu| menu.origin())
 8546    }
 8547
 8548    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8549        self.context_menu_options = Some(options);
 8550    }
 8551
 8552    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8553    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8554
 8555    fn render_edit_prediction_popover(
 8556        &mut self,
 8557        text_bounds: &Bounds<Pixels>,
 8558        content_origin: gpui::Point<Pixels>,
 8559        right_margin: Pixels,
 8560        editor_snapshot: &EditorSnapshot,
 8561        visible_row_range: Range<DisplayRow>,
 8562        scroll_top: f32,
 8563        scroll_bottom: f32,
 8564        line_layouts: &[LineWithInvisibles],
 8565        line_height: Pixels,
 8566        scroll_pixel_position: gpui::Point<Pixels>,
 8567        newest_selection_head: Option<DisplayPoint>,
 8568        editor_width: Pixels,
 8569        style: &EditorStyle,
 8570        window: &mut Window,
 8571        cx: &mut App,
 8572    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8573        if self.mode().is_minimap() {
 8574            return None;
 8575        }
 8576        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8577
 8578        if self.edit_prediction_visible_in_cursor_popover(true) {
 8579            return None;
 8580        }
 8581
 8582        match &active_edit_prediction.completion {
 8583            EditPrediction::Move { target, .. } => {
 8584                let target_display_point = target.to_display_point(editor_snapshot);
 8585
 8586                if self.edit_prediction_requires_modifier() {
 8587                    if !self.edit_prediction_preview_is_active() {
 8588                        return None;
 8589                    }
 8590
 8591                    self.render_edit_prediction_modifier_jump_popover(
 8592                        text_bounds,
 8593                        content_origin,
 8594                        visible_row_range,
 8595                        line_layouts,
 8596                        line_height,
 8597                        scroll_pixel_position,
 8598                        newest_selection_head,
 8599                        target_display_point,
 8600                        window,
 8601                        cx,
 8602                    )
 8603                } else {
 8604                    self.render_edit_prediction_eager_jump_popover(
 8605                        text_bounds,
 8606                        content_origin,
 8607                        editor_snapshot,
 8608                        visible_row_range,
 8609                        scroll_top,
 8610                        scroll_bottom,
 8611                        line_height,
 8612                        scroll_pixel_position,
 8613                        target_display_point,
 8614                        editor_width,
 8615                        window,
 8616                        cx,
 8617                    )
 8618                }
 8619            }
 8620            EditPrediction::Edit {
 8621                display_mode: EditDisplayMode::Inline,
 8622                ..
 8623            } => None,
 8624            EditPrediction::Edit {
 8625                display_mode: EditDisplayMode::TabAccept,
 8626                edits,
 8627                ..
 8628            } => {
 8629                let range = &edits.first()?.0;
 8630                let target_display_point = range.end.to_display_point(editor_snapshot);
 8631
 8632                self.render_edit_prediction_end_of_line_popover(
 8633                    "Accept",
 8634                    editor_snapshot,
 8635                    visible_row_range,
 8636                    target_display_point,
 8637                    line_height,
 8638                    scroll_pixel_position,
 8639                    content_origin,
 8640                    editor_width,
 8641                    window,
 8642                    cx,
 8643                )
 8644            }
 8645            EditPrediction::Edit {
 8646                edits,
 8647                edit_preview,
 8648                display_mode: EditDisplayMode::DiffPopover,
 8649                snapshot,
 8650            } => self.render_edit_prediction_diff_popover(
 8651                text_bounds,
 8652                content_origin,
 8653                right_margin,
 8654                editor_snapshot,
 8655                visible_row_range,
 8656                line_layouts,
 8657                line_height,
 8658                scroll_pixel_position,
 8659                newest_selection_head,
 8660                editor_width,
 8661                style,
 8662                edits,
 8663                edit_preview,
 8664                snapshot,
 8665                window,
 8666                cx,
 8667            ),
 8668        }
 8669    }
 8670
 8671    fn render_edit_prediction_modifier_jump_popover(
 8672        &mut self,
 8673        text_bounds: &Bounds<Pixels>,
 8674        content_origin: gpui::Point<Pixels>,
 8675        visible_row_range: Range<DisplayRow>,
 8676        line_layouts: &[LineWithInvisibles],
 8677        line_height: Pixels,
 8678        scroll_pixel_position: gpui::Point<Pixels>,
 8679        newest_selection_head: Option<DisplayPoint>,
 8680        target_display_point: DisplayPoint,
 8681        window: &mut Window,
 8682        cx: &mut App,
 8683    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8684        let scrolled_content_origin =
 8685            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8686
 8687        const SCROLL_PADDING_Y: Pixels = px(12.);
 8688
 8689        if target_display_point.row() < visible_row_range.start {
 8690            return self.render_edit_prediction_scroll_popover(
 8691                |_| SCROLL_PADDING_Y,
 8692                IconName::ArrowUp,
 8693                visible_row_range,
 8694                line_layouts,
 8695                newest_selection_head,
 8696                scrolled_content_origin,
 8697                window,
 8698                cx,
 8699            );
 8700        } else if target_display_point.row() >= visible_row_range.end {
 8701            return self.render_edit_prediction_scroll_popover(
 8702                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8703                IconName::ArrowDown,
 8704                visible_row_range,
 8705                line_layouts,
 8706                newest_selection_head,
 8707                scrolled_content_origin,
 8708                window,
 8709                cx,
 8710            );
 8711        }
 8712
 8713        const POLE_WIDTH: Pixels = px(2.);
 8714
 8715        let line_layout =
 8716            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8717        let target_column = target_display_point.column() as usize;
 8718
 8719        let target_x = line_layout.x_for_index(target_column);
 8720        let target_y =
 8721            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8722
 8723        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8724
 8725        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8726        border_color.l += 0.001;
 8727
 8728        let mut element = v_flex()
 8729            .items_end()
 8730            .when(flag_on_right, |el| el.items_start())
 8731            .child(if flag_on_right {
 8732                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8733                    .rounded_bl(px(0.))
 8734                    .rounded_tl(px(0.))
 8735                    .border_l_2()
 8736                    .border_color(border_color)
 8737            } else {
 8738                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8739                    .rounded_br(px(0.))
 8740                    .rounded_tr(px(0.))
 8741                    .border_r_2()
 8742                    .border_color(border_color)
 8743            })
 8744            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8745            .into_any();
 8746
 8747        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8748
 8749        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8750            - point(
 8751                if flag_on_right {
 8752                    POLE_WIDTH
 8753                } else {
 8754                    size.width - POLE_WIDTH
 8755                },
 8756                size.height - line_height,
 8757            );
 8758
 8759        origin.x = origin.x.max(content_origin.x);
 8760
 8761        element.prepaint_at(origin, window, cx);
 8762
 8763        Some((element, origin))
 8764    }
 8765
 8766    fn render_edit_prediction_scroll_popover(
 8767        &mut self,
 8768        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8769        scroll_icon: IconName,
 8770        visible_row_range: Range<DisplayRow>,
 8771        line_layouts: &[LineWithInvisibles],
 8772        newest_selection_head: Option<DisplayPoint>,
 8773        scrolled_content_origin: gpui::Point<Pixels>,
 8774        window: &mut Window,
 8775        cx: &mut App,
 8776    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8777        let mut element = self
 8778            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8779            .into_any();
 8780
 8781        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8782
 8783        let cursor = newest_selection_head?;
 8784        let cursor_row_layout =
 8785            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8786        let cursor_column = cursor.column() as usize;
 8787
 8788        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8789
 8790        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8791
 8792        element.prepaint_at(origin, window, cx);
 8793        Some((element, origin))
 8794    }
 8795
 8796    fn render_edit_prediction_eager_jump_popover(
 8797        &mut self,
 8798        text_bounds: &Bounds<Pixels>,
 8799        content_origin: gpui::Point<Pixels>,
 8800        editor_snapshot: &EditorSnapshot,
 8801        visible_row_range: Range<DisplayRow>,
 8802        scroll_top: f32,
 8803        scroll_bottom: f32,
 8804        line_height: Pixels,
 8805        scroll_pixel_position: gpui::Point<Pixels>,
 8806        target_display_point: DisplayPoint,
 8807        editor_width: Pixels,
 8808        window: &mut Window,
 8809        cx: &mut App,
 8810    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8811        if target_display_point.row().as_f32() < scroll_top {
 8812            let mut element = self
 8813                .render_edit_prediction_line_popover(
 8814                    "Jump to Edit",
 8815                    Some(IconName::ArrowUp),
 8816                    window,
 8817                    cx,
 8818                )?
 8819                .into_any();
 8820
 8821            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8822            let offset = point(
 8823                (text_bounds.size.width - size.width) / 2.,
 8824                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8825            );
 8826
 8827            let origin = text_bounds.origin + offset;
 8828            element.prepaint_at(origin, window, cx);
 8829            Some((element, origin))
 8830        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8831            let mut element = self
 8832                .render_edit_prediction_line_popover(
 8833                    "Jump to Edit",
 8834                    Some(IconName::ArrowDown),
 8835                    window,
 8836                    cx,
 8837                )?
 8838                .into_any();
 8839
 8840            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8841            let offset = point(
 8842                (text_bounds.size.width - size.width) / 2.,
 8843                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8844            );
 8845
 8846            let origin = text_bounds.origin + offset;
 8847            element.prepaint_at(origin, window, cx);
 8848            Some((element, origin))
 8849        } else {
 8850            self.render_edit_prediction_end_of_line_popover(
 8851                "Jump to Edit",
 8852                editor_snapshot,
 8853                visible_row_range,
 8854                target_display_point,
 8855                line_height,
 8856                scroll_pixel_position,
 8857                content_origin,
 8858                editor_width,
 8859                window,
 8860                cx,
 8861            )
 8862        }
 8863    }
 8864
 8865    fn render_edit_prediction_end_of_line_popover(
 8866        self: &mut Editor,
 8867        label: &'static str,
 8868        editor_snapshot: &EditorSnapshot,
 8869        visible_row_range: Range<DisplayRow>,
 8870        target_display_point: DisplayPoint,
 8871        line_height: Pixels,
 8872        scroll_pixel_position: gpui::Point<Pixels>,
 8873        content_origin: gpui::Point<Pixels>,
 8874        editor_width: Pixels,
 8875        window: &mut Window,
 8876        cx: &mut App,
 8877    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8878        let target_line_end = DisplayPoint::new(
 8879            target_display_point.row(),
 8880            editor_snapshot.line_len(target_display_point.row()),
 8881        );
 8882
 8883        let mut element = self
 8884            .render_edit_prediction_line_popover(label, None, window, cx)?
 8885            .into_any();
 8886
 8887        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8888
 8889        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8890
 8891        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8892        let mut origin = start_point
 8893            + line_origin
 8894            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8895        origin.x = origin.x.max(content_origin.x);
 8896
 8897        let max_x = content_origin.x + editor_width - size.width;
 8898
 8899        if origin.x > max_x {
 8900            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8901
 8902            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8903                origin.y += offset;
 8904                IconName::ArrowUp
 8905            } else {
 8906                origin.y -= offset;
 8907                IconName::ArrowDown
 8908            };
 8909
 8910            element = self
 8911                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8912                .into_any();
 8913
 8914            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8915
 8916            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8917        }
 8918
 8919        element.prepaint_at(origin, window, cx);
 8920        Some((element, origin))
 8921    }
 8922
 8923    fn render_edit_prediction_diff_popover(
 8924        self: &Editor,
 8925        text_bounds: &Bounds<Pixels>,
 8926        content_origin: gpui::Point<Pixels>,
 8927        right_margin: Pixels,
 8928        editor_snapshot: &EditorSnapshot,
 8929        visible_row_range: Range<DisplayRow>,
 8930        line_layouts: &[LineWithInvisibles],
 8931        line_height: Pixels,
 8932        scroll_pixel_position: gpui::Point<Pixels>,
 8933        newest_selection_head: Option<DisplayPoint>,
 8934        editor_width: Pixels,
 8935        style: &EditorStyle,
 8936        edits: &Vec<(Range<Anchor>, String)>,
 8937        edit_preview: &Option<language::EditPreview>,
 8938        snapshot: &language::BufferSnapshot,
 8939        window: &mut Window,
 8940        cx: &mut App,
 8941    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8942        let edit_start = edits
 8943            .first()
 8944            .unwrap()
 8945            .0
 8946            .start
 8947            .to_display_point(editor_snapshot);
 8948        let edit_end = edits
 8949            .last()
 8950            .unwrap()
 8951            .0
 8952            .end
 8953            .to_display_point(editor_snapshot);
 8954
 8955        let is_visible = visible_row_range.contains(&edit_start.row())
 8956            || visible_row_range.contains(&edit_end.row());
 8957        if !is_visible {
 8958            return None;
 8959        }
 8960
 8961        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8962            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8963        } else {
 8964            // Fallback for providers without edit_preview
 8965            crate::edit_prediction_fallback_text(edits, cx)
 8966        };
 8967
 8968        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8969        let line_count = highlighted_edits.text.lines().count();
 8970
 8971        const BORDER_WIDTH: Pixels = px(1.);
 8972
 8973        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8974        let has_keybind = keybind.is_some();
 8975
 8976        let mut element = h_flex()
 8977            .items_start()
 8978            .child(
 8979                h_flex()
 8980                    .bg(cx.theme().colors().editor_background)
 8981                    .border(BORDER_WIDTH)
 8982                    .shadow_xs()
 8983                    .border_color(cx.theme().colors().border)
 8984                    .rounded_l_lg()
 8985                    .when(line_count > 1, |el| el.rounded_br_lg())
 8986                    .pr_1()
 8987                    .child(styled_text),
 8988            )
 8989            .child(
 8990                h_flex()
 8991                    .h(line_height + BORDER_WIDTH * 2.)
 8992                    .px_1p5()
 8993                    .gap_1()
 8994                    // Workaround: For some reason, there's a gap if we don't do this
 8995                    .ml(-BORDER_WIDTH)
 8996                    .shadow(vec![gpui::BoxShadow {
 8997                        color: gpui::black().opacity(0.05),
 8998                        offset: point(px(1.), px(1.)),
 8999                        blur_radius: px(2.),
 9000                        spread_radius: px(0.),
 9001                    }])
 9002                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9003                    .border(BORDER_WIDTH)
 9004                    .border_color(cx.theme().colors().border)
 9005                    .rounded_r_lg()
 9006                    .id("edit_prediction_diff_popover_keybind")
 9007                    .when(!has_keybind, |el| {
 9008                        let status_colors = cx.theme().status();
 9009
 9010                        el.bg(status_colors.error_background)
 9011                            .border_color(status_colors.error.opacity(0.6))
 9012                            .child(Icon::new(IconName::Info).color(Color::Error))
 9013                            .cursor_default()
 9014                            .hoverable_tooltip(move |_window, cx| {
 9015                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9016                            })
 9017                    })
 9018                    .children(keybind),
 9019            )
 9020            .into_any();
 9021
 9022        let longest_row =
 9023            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9024        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9025            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9026        } else {
 9027            layout_line(
 9028                longest_row,
 9029                editor_snapshot,
 9030                style,
 9031                editor_width,
 9032                |_| false,
 9033                window,
 9034                cx,
 9035            )
 9036            .width
 9037        };
 9038
 9039        let viewport_bounds =
 9040            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9041                right: -right_margin,
 9042                ..Default::default()
 9043            });
 9044
 9045        let x_after_longest =
 9046            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9047                - scroll_pixel_position.x;
 9048
 9049        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9050
 9051        // Fully visible if it can be displayed within the window (allow overlapping other
 9052        // panes). However, this is only allowed if the popover starts within text_bounds.
 9053        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9054            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9055
 9056        let mut origin = if can_position_to_the_right {
 9057            point(
 9058                x_after_longest,
 9059                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9060                    - scroll_pixel_position.y,
 9061            )
 9062        } else {
 9063            let cursor_row = newest_selection_head.map(|head| head.row());
 9064            let above_edit = edit_start
 9065                .row()
 9066                .0
 9067                .checked_sub(line_count as u32)
 9068                .map(DisplayRow);
 9069            let below_edit = Some(edit_end.row() + 1);
 9070            let above_cursor =
 9071                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9072            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9073
 9074            // Place the edit popover adjacent to the edit if there is a location
 9075            // available that is onscreen and does not obscure the cursor. Otherwise,
 9076            // place it adjacent to the cursor.
 9077            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9078                .into_iter()
 9079                .flatten()
 9080                .find(|&start_row| {
 9081                    let end_row = start_row + line_count as u32;
 9082                    visible_row_range.contains(&start_row)
 9083                        && visible_row_range.contains(&end_row)
 9084                        && cursor_row
 9085                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9086                })?;
 9087
 9088            content_origin
 9089                + point(
 9090                    -scroll_pixel_position.x,
 9091                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9092                )
 9093        };
 9094
 9095        origin.x -= BORDER_WIDTH;
 9096
 9097        window.defer_draw(element, origin, 1);
 9098
 9099        // Do not return an element, since it will already be drawn due to defer_draw.
 9100        None
 9101    }
 9102
 9103    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9104        px(30.)
 9105    }
 9106
 9107    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9108        if self.read_only(cx) {
 9109            cx.theme().players().read_only()
 9110        } else {
 9111            self.style.as_ref().unwrap().local_player
 9112        }
 9113    }
 9114
 9115    fn render_edit_prediction_accept_keybind(
 9116        &self,
 9117        window: &mut Window,
 9118        cx: &App,
 9119    ) -> Option<AnyElement> {
 9120        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9121        let accept_keystroke = accept_binding.keystroke()?;
 9122
 9123        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9124
 9125        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9126            Color::Accent
 9127        } else {
 9128            Color::Muted
 9129        };
 9130
 9131        h_flex()
 9132            .px_0p5()
 9133            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9134            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9135            .text_size(TextSize::XSmall.rems(cx))
 9136            .child(h_flex().children(ui::render_modifiers(
 9137                accept_keystroke.modifiers(),
 9138                PlatformStyle::platform(),
 9139                Some(modifiers_color),
 9140                Some(IconSize::XSmall.rems().into()),
 9141                true,
 9142            )))
 9143            .when(is_platform_style_mac, |parent| {
 9144                parent.child(accept_keystroke.key().to_string())
 9145            })
 9146            .when(!is_platform_style_mac, |parent| {
 9147                parent.child(
 9148                    Key::new(
 9149                        util::capitalize(accept_keystroke.key()),
 9150                        Some(Color::Default),
 9151                    )
 9152                    .size(Some(IconSize::XSmall.rems().into())),
 9153                )
 9154            })
 9155            .into_any()
 9156            .into()
 9157    }
 9158
 9159    fn render_edit_prediction_line_popover(
 9160        &self,
 9161        label: impl Into<SharedString>,
 9162        icon: Option<IconName>,
 9163        window: &mut Window,
 9164        cx: &App,
 9165    ) -> Option<Stateful<Div>> {
 9166        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9167
 9168        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9169        let has_keybind = keybind.is_some();
 9170
 9171        let result = h_flex()
 9172            .id("ep-line-popover")
 9173            .py_0p5()
 9174            .pl_1()
 9175            .pr(padding_right)
 9176            .gap_1()
 9177            .rounded_md()
 9178            .border_1()
 9179            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9180            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9181            .shadow_xs()
 9182            .when(!has_keybind, |el| {
 9183                let status_colors = cx.theme().status();
 9184
 9185                el.bg(status_colors.error_background)
 9186                    .border_color(status_colors.error.opacity(0.6))
 9187                    .pl_2()
 9188                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9189                    .cursor_default()
 9190                    .hoverable_tooltip(move |_window, cx| {
 9191                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9192                    })
 9193            })
 9194            .children(keybind)
 9195            .child(
 9196                Label::new(label)
 9197                    .size(LabelSize::Small)
 9198                    .when(!has_keybind, |el| {
 9199                        el.color(cx.theme().status().error.into()).strikethrough()
 9200                    }),
 9201            )
 9202            .when(!has_keybind, |el| {
 9203                el.child(
 9204                    h_flex().ml_1().child(
 9205                        Icon::new(IconName::Info)
 9206                            .size(IconSize::Small)
 9207                            .color(cx.theme().status().error.into()),
 9208                    ),
 9209                )
 9210            })
 9211            .when_some(icon, |element, icon| {
 9212                element.child(
 9213                    div()
 9214                        .mt(px(1.5))
 9215                        .child(Icon::new(icon).size(IconSize::Small)),
 9216                )
 9217            });
 9218
 9219        Some(result)
 9220    }
 9221
 9222    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9223        let accent_color = cx.theme().colors().text_accent;
 9224        let editor_bg_color = cx.theme().colors().editor_background;
 9225        editor_bg_color.blend(accent_color.opacity(0.1))
 9226    }
 9227
 9228    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9229        let accent_color = cx.theme().colors().text_accent;
 9230        let editor_bg_color = cx.theme().colors().editor_background;
 9231        editor_bg_color.blend(accent_color.opacity(0.6))
 9232    }
 9233    fn get_prediction_provider_icon_name(
 9234        provider: &Option<RegisteredEditPredictionProvider>,
 9235    ) -> IconName {
 9236        match provider {
 9237            Some(provider) => match provider.provider.name() {
 9238                "copilot" => IconName::Copilot,
 9239                "supermaven" => IconName::Supermaven,
 9240                _ => IconName::ZedPredict,
 9241            },
 9242            None => IconName::ZedPredict,
 9243        }
 9244    }
 9245
 9246    fn render_edit_prediction_cursor_popover(
 9247        &self,
 9248        min_width: Pixels,
 9249        max_width: Pixels,
 9250        cursor_point: Point,
 9251        style: &EditorStyle,
 9252        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9253        _window: &Window,
 9254        cx: &mut Context<Editor>,
 9255    ) -> Option<AnyElement> {
 9256        let provider = self.edit_prediction_provider.as_ref()?;
 9257        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9258
 9259        let is_refreshing = provider.provider.is_refreshing(cx);
 9260
 9261        fn pending_completion_container(icon: IconName) -> Div {
 9262            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9263        }
 9264
 9265        let completion = match &self.active_edit_prediction {
 9266            Some(prediction) => {
 9267                if !self.has_visible_completions_menu() {
 9268                    const RADIUS: Pixels = px(6.);
 9269                    const BORDER_WIDTH: Pixels = px(1.);
 9270
 9271                    return Some(
 9272                        h_flex()
 9273                            .elevation_2(cx)
 9274                            .border(BORDER_WIDTH)
 9275                            .border_color(cx.theme().colors().border)
 9276                            .when(accept_keystroke.is_none(), |el| {
 9277                                el.border_color(cx.theme().status().error)
 9278                            })
 9279                            .rounded(RADIUS)
 9280                            .rounded_tl(px(0.))
 9281                            .overflow_hidden()
 9282                            .child(div().px_1p5().child(match &prediction.completion {
 9283                                EditPrediction::Move { target, snapshot } => {
 9284                                    use text::ToPoint as _;
 9285                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9286                                    {
 9287                                        Icon::new(IconName::ZedPredictDown)
 9288                                    } else {
 9289                                        Icon::new(IconName::ZedPredictUp)
 9290                                    }
 9291                                }
 9292                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9293                            }))
 9294                            .child(
 9295                                h_flex()
 9296                                    .gap_1()
 9297                                    .py_1()
 9298                                    .px_2()
 9299                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9300                                    .border_l_1()
 9301                                    .border_color(cx.theme().colors().border)
 9302                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9303                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9304                                        el.child(
 9305                                            Label::new("Hold")
 9306                                                .size(LabelSize::Small)
 9307                                                .when(accept_keystroke.is_none(), |el| {
 9308                                                    el.strikethrough()
 9309                                                })
 9310                                                .line_height_style(LineHeightStyle::UiLabel),
 9311                                        )
 9312                                    })
 9313                                    .id("edit_prediction_cursor_popover_keybind")
 9314                                    .when(accept_keystroke.is_none(), |el| {
 9315                                        let status_colors = cx.theme().status();
 9316
 9317                                        el.bg(status_colors.error_background)
 9318                                            .border_color(status_colors.error.opacity(0.6))
 9319                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9320                                            .cursor_default()
 9321                                            .hoverable_tooltip(move |_window, cx| {
 9322                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9323                                                    .into()
 9324                                            })
 9325                                    })
 9326                                    .when_some(
 9327                                        accept_keystroke.as_ref(),
 9328                                        |el, accept_keystroke| {
 9329                                            el.child(h_flex().children(ui::render_modifiers(
 9330                                                accept_keystroke.modifiers(),
 9331                                                PlatformStyle::platform(),
 9332                                                Some(Color::Default),
 9333                                                Some(IconSize::XSmall.rems().into()),
 9334                                                false,
 9335                                            )))
 9336                                        },
 9337                                    ),
 9338                            )
 9339                            .into_any(),
 9340                    );
 9341                }
 9342
 9343                self.render_edit_prediction_cursor_popover_preview(
 9344                    prediction,
 9345                    cursor_point,
 9346                    style,
 9347                    cx,
 9348                )?
 9349            }
 9350
 9351            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9352                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9353                    stale_completion,
 9354                    cursor_point,
 9355                    style,
 9356                    cx,
 9357                )?,
 9358
 9359                None => pending_completion_container(provider_icon)
 9360                    .child(Label::new("...").size(LabelSize::Small)),
 9361            },
 9362
 9363            None => pending_completion_container(provider_icon)
 9364                .child(Label::new("...").size(LabelSize::Small)),
 9365        };
 9366
 9367        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9368            completion
 9369                .with_animation(
 9370                    "loading-completion",
 9371                    Animation::new(Duration::from_secs(2))
 9372                        .repeat()
 9373                        .with_easing(pulsating_between(0.4, 0.8)),
 9374                    |label, delta| label.opacity(delta),
 9375                )
 9376                .into_any_element()
 9377        } else {
 9378            completion.into_any_element()
 9379        };
 9380
 9381        let has_completion = self.active_edit_prediction.is_some();
 9382
 9383        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9384        Some(
 9385            h_flex()
 9386                .min_w(min_width)
 9387                .max_w(max_width)
 9388                .flex_1()
 9389                .elevation_2(cx)
 9390                .border_color(cx.theme().colors().border)
 9391                .child(
 9392                    div()
 9393                        .flex_1()
 9394                        .py_1()
 9395                        .px_2()
 9396                        .overflow_hidden()
 9397                        .child(completion),
 9398                )
 9399                .when_some(accept_keystroke, |el, accept_keystroke| {
 9400                    if !accept_keystroke.modifiers().modified() {
 9401                        return el;
 9402                    }
 9403
 9404                    el.child(
 9405                        h_flex()
 9406                            .h_full()
 9407                            .border_l_1()
 9408                            .rounded_r_lg()
 9409                            .border_color(cx.theme().colors().border)
 9410                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9411                            .gap_1()
 9412                            .py_1()
 9413                            .px_2()
 9414                            .child(
 9415                                h_flex()
 9416                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9417                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9418                                    .child(h_flex().children(ui::render_modifiers(
 9419                                        accept_keystroke.modifiers(),
 9420                                        PlatformStyle::platform(),
 9421                                        Some(if !has_completion {
 9422                                            Color::Muted
 9423                                        } else {
 9424                                            Color::Default
 9425                                        }),
 9426                                        None,
 9427                                        false,
 9428                                    ))),
 9429                            )
 9430                            .child(Label::new("Preview").into_any_element())
 9431                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9432                    )
 9433                })
 9434                .into_any(),
 9435        )
 9436    }
 9437
 9438    fn render_edit_prediction_cursor_popover_preview(
 9439        &self,
 9440        completion: &EditPredictionState,
 9441        cursor_point: Point,
 9442        style: &EditorStyle,
 9443        cx: &mut Context<Editor>,
 9444    ) -> Option<Div> {
 9445        use text::ToPoint as _;
 9446
 9447        fn render_relative_row_jump(
 9448            prefix: impl Into<String>,
 9449            current_row: u32,
 9450            target_row: u32,
 9451        ) -> Div {
 9452            let (row_diff, arrow) = if target_row < current_row {
 9453                (current_row - target_row, IconName::ArrowUp)
 9454            } else {
 9455                (target_row - current_row, IconName::ArrowDown)
 9456            };
 9457
 9458            h_flex()
 9459                .child(
 9460                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9461                        .color(Color::Muted)
 9462                        .size(LabelSize::Small),
 9463                )
 9464                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9465        }
 9466
 9467        let supports_jump = self
 9468            .edit_prediction_provider
 9469            .as_ref()
 9470            .map(|provider| provider.provider.supports_jump_to_edit())
 9471            .unwrap_or(true);
 9472
 9473        match &completion.completion {
 9474            EditPrediction::Move {
 9475                target, snapshot, ..
 9476            } => {
 9477                if !supports_jump {
 9478                    return None;
 9479                }
 9480
 9481                Some(
 9482                    h_flex()
 9483                        .px_2()
 9484                        .gap_2()
 9485                        .flex_1()
 9486                        .child(
 9487                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9488                                Icon::new(IconName::ZedPredictDown)
 9489                            } else {
 9490                                Icon::new(IconName::ZedPredictUp)
 9491                            },
 9492                        )
 9493                        .child(Label::new("Jump to Edit")),
 9494                )
 9495            }
 9496
 9497            EditPrediction::Edit {
 9498                edits,
 9499                edit_preview,
 9500                snapshot,
 9501                display_mode: _,
 9502            } => {
 9503                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9504
 9505                let (highlighted_edits, has_more_lines) =
 9506                    if let Some(edit_preview) = edit_preview.as_ref() {
 9507                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9508                            .first_line_preview()
 9509                    } else {
 9510                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9511                    };
 9512
 9513                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9514                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9515
 9516                let preview = h_flex()
 9517                    .gap_1()
 9518                    .min_w_16()
 9519                    .child(styled_text)
 9520                    .when(has_more_lines, |parent| parent.child(""));
 9521
 9522                let left = if supports_jump && first_edit_row != cursor_point.row {
 9523                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9524                        .into_any_element()
 9525                } else {
 9526                    let icon_name =
 9527                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9528                    Icon::new(icon_name).into_any_element()
 9529                };
 9530
 9531                Some(
 9532                    h_flex()
 9533                        .h_full()
 9534                        .flex_1()
 9535                        .gap_2()
 9536                        .pr_1()
 9537                        .overflow_x_hidden()
 9538                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9539                        .child(left)
 9540                        .child(preview),
 9541                )
 9542            }
 9543        }
 9544    }
 9545
 9546    pub fn render_context_menu(
 9547        &self,
 9548        style: &EditorStyle,
 9549        max_height_in_lines: u32,
 9550        window: &mut Window,
 9551        cx: &mut Context<Editor>,
 9552    ) -> Option<AnyElement> {
 9553        let menu = self.context_menu.borrow();
 9554        let menu = menu.as_ref()?;
 9555        if !menu.visible() {
 9556            return None;
 9557        };
 9558        Some(menu.render(style, max_height_in_lines, window, cx))
 9559    }
 9560
 9561    fn render_context_menu_aside(
 9562        &mut self,
 9563        max_size: Size<Pixels>,
 9564        window: &mut Window,
 9565        cx: &mut Context<Editor>,
 9566    ) -> Option<AnyElement> {
 9567        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9568            if menu.visible() {
 9569                menu.render_aside(max_size, window, cx)
 9570            } else {
 9571                None
 9572            }
 9573        })
 9574    }
 9575
 9576    fn hide_context_menu(
 9577        &mut self,
 9578        window: &mut Window,
 9579        cx: &mut Context<Self>,
 9580    ) -> Option<CodeContextMenu> {
 9581        cx.notify();
 9582        self.completion_tasks.clear();
 9583        let context_menu = self.context_menu.borrow_mut().take();
 9584        self.stale_edit_prediction_in_menu.take();
 9585        self.update_visible_edit_prediction(window, cx);
 9586        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9587            && let Some(completion_provider) = &self.completion_provider
 9588        {
 9589            completion_provider.selection_changed(None, window, cx);
 9590        }
 9591        context_menu
 9592    }
 9593
 9594    fn show_snippet_choices(
 9595        &mut self,
 9596        choices: &Vec<String>,
 9597        selection: Range<Anchor>,
 9598        cx: &mut Context<Self>,
 9599    ) {
 9600        let Some((_, buffer, _)) = self
 9601            .buffer()
 9602            .read(cx)
 9603            .excerpt_containing(selection.start, cx)
 9604        else {
 9605            return;
 9606        };
 9607        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9608        else {
 9609            return;
 9610        };
 9611        if buffer != end_buffer {
 9612            log::error!("expected anchor range to have matching buffer IDs");
 9613            return;
 9614        }
 9615
 9616        let id = post_inc(&mut self.next_completion_id);
 9617        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9618        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9619            CompletionsMenu::new_snippet_choices(
 9620                id,
 9621                true,
 9622                choices,
 9623                selection,
 9624                buffer,
 9625                snippet_sort_order,
 9626            ),
 9627        ));
 9628    }
 9629
 9630    pub fn insert_snippet(
 9631        &mut self,
 9632        insertion_ranges: &[Range<usize>],
 9633        snippet: Snippet,
 9634        window: &mut Window,
 9635        cx: &mut Context<Self>,
 9636    ) -> Result<()> {
 9637        struct Tabstop<T> {
 9638            is_end_tabstop: bool,
 9639            ranges: Vec<Range<T>>,
 9640            choices: Option<Vec<String>>,
 9641        }
 9642
 9643        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9644            let snippet_text: Arc<str> = snippet.text.clone().into();
 9645            let edits = insertion_ranges
 9646                .iter()
 9647                .cloned()
 9648                .map(|range| (range, snippet_text.clone()));
 9649            let autoindent_mode = AutoindentMode::Block {
 9650                original_indent_columns: Vec::new(),
 9651            };
 9652            buffer.edit(edits, Some(autoindent_mode), cx);
 9653
 9654            let snapshot = &*buffer.read(cx);
 9655            let snippet = &snippet;
 9656            snippet
 9657                .tabstops
 9658                .iter()
 9659                .map(|tabstop| {
 9660                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9661                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9662                    });
 9663                    let mut tabstop_ranges = tabstop
 9664                        .ranges
 9665                        .iter()
 9666                        .flat_map(|tabstop_range| {
 9667                            let mut delta = 0_isize;
 9668                            insertion_ranges.iter().map(move |insertion_range| {
 9669                                let insertion_start = insertion_range.start as isize + delta;
 9670                                delta +=
 9671                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9672
 9673                                let start = ((insertion_start + tabstop_range.start) as usize)
 9674                                    .min(snapshot.len());
 9675                                let end = ((insertion_start + tabstop_range.end) as usize)
 9676                                    .min(snapshot.len());
 9677                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9678                            })
 9679                        })
 9680                        .collect::<Vec<_>>();
 9681                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9682
 9683                    Tabstop {
 9684                        is_end_tabstop,
 9685                        ranges: tabstop_ranges,
 9686                        choices: tabstop.choices.clone(),
 9687                    }
 9688                })
 9689                .collect::<Vec<_>>()
 9690        });
 9691        if let Some(tabstop) = tabstops.first() {
 9692            self.change_selections(Default::default(), window, cx, |s| {
 9693                // Reverse order so that the first range is the newest created selection.
 9694                // Completions will use it and autoscroll will prioritize it.
 9695                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9696            });
 9697
 9698            if let Some(choices) = &tabstop.choices
 9699                && let Some(selection) = tabstop.ranges.first()
 9700            {
 9701                self.show_snippet_choices(choices, selection.clone(), cx)
 9702            }
 9703
 9704            // If we're already at the last tabstop and it's at the end of the snippet,
 9705            // we're done, we don't need to keep the state around.
 9706            if !tabstop.is_end_tabstop {
 9707                let choices = tabstops
 9708                    .iter()
 9709                    .map(|tabstop| tabstop.choices.clone())
 9710                    .collect();
 9711
 9712                let ranges = tabstops
 9713                    .into_iter()
 9714                    .map(|tabstop| tabstop.ranges)
 9715                    .collect::<Vec<_>>();
 9716
 9717                self.snippet_stack.push(SnippetState {
 9718                    active_index: 0,
 9719                    ranges,
 9720                    choices,
 9721                });
 9722            }
 9723
 9724            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9725            if self.autoclose_regions.is_empty() {
 9726                let snapshot = self.buffer.read(cx).snapshot(cx);
 9727                let mut all_selections = self.selections.all::<Point>(cx);
 9728                for selection in &mut all_selections {
 9729                    let selection_head = selection.head();
 9730                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9731                        continue;
 9732                    };
 9733
 9734                    let mut bracket_pair = None;
 9735                    let max_lookup_length = scope
 9736                        .brackets()
 9737                        .map(|(pair, _)| {
 9738                            pair.start
 9739                                .as_str()
 9740                                .chars()
 9741                                .count()
 9742                                .max(pair.end.as_str().chars().count())
 9743                        })
 9744                        .max();
 9745                    if let Some(max_lookup_length) = max_lookup_length {
 9746                        let next_text = snapshot
 9747                            .chars_at(selection_head)
 9748                            .take(max_lookup_length)
 9749                            .collect::<String>();
 9750                        let prev_text = snapshot
 9751                            .reversed_chars_at(selection_head)
 9752                            .take(max_lookup_length)
 9753                            .collect::<String>();
 9754
 9755                        for (pair, enabled) in scope.brackets() {
 9756                            if enabled
 9757                                && pair.close
 9758                                && prev_text.starts_with(pair.start.as_str())
 9759                                && next_text.starts_with(pair.end.as_str())
 9760                            {
 9761                                bracket_pair = Some(pair.clone());
 9762                                break;
 9763                            }
 9764                        }
 9765                    }
 9766
 9767                    if let Some(pair) = bracket_pair {
 9768                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9769                        let autoclose_enabled =
 9770                            self.use_autoclose && snapshot_settings.use_autoclose;
 9771                        if autoclose_enabled {
 9772                            let start = snapshot.anchor_after(selection_head);
 9773                            let end = snapshot.anchor_after(selection_head);
 9774                            self.autoclose_regions.push(AutocloseRegion {
 9775                                selection_id: selection.id,
 9776                                range: start..end,
 9777                                pair,
 9778                            });
 9779                        }
 9780                    }
 9781                }
 9782            }
 9783        }
 9784        Ok(())
 9785    }
 9786
 9787    pub fn move_to_next_snippet_tabstop(
 9788        &mut self,
 9789        window: &mut Window,
 9790        cx: &mut Context<Self>,
 9791    ) -> bool {
 9792        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9793    }
 9794
 9795    pub fn move_to_prev_snippet_tabstop(
 9796        &mut self,
 9797        window: &mut Window,
 9798        cx: &mut Context<Self>,
 9799    ) -> bool {
 9800        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9801    }
 9802
 9803    pub fn move_to_snippet_tabstop(
 9804        &mut self,
 9805        bias: Bias,
 9806        window: &mut Window,
 9807        cx: &mut Context<Self>,
 9808    ) -> bool {
 9809        if let Some(mut snippet) = self.snippet_stack.pop() {
 9810            match bias {
 9811                Bias::Left => {
 9812                    if snippet.active_index > 0 {
 9813                        snippet.active_index -= 1;
 9814                    } else {
 9815                        self.snippet_stack.push(snippet);
 9816                        return false;
 9817                    }
 9818                }
 9819                Bias::Right => {
 9820                    if snippet.active_index + 1 < snippet.ranges.len() {
 9821                        snippet.active_index += 1;
 9822                    } else {
 9823                        self.snippet_stack.push(snippet);
 9824                        return false;
 9825                    }
 9826                }
 9827            }
 9828            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9829                self.change_selections(Default::default(), window, cx, |s| {
 9830                    // Reverse order so that the first range is the newest created selection.
 9831                    // Completions will use it and autoscroll will prioritize it.
 9832                    s.select_ranges(current_ranges.iter().rev().cloned())
 9833                });
 9834
 9835                if let Some(choices) = &snippet.choices[snippet.active_index]
 9836                    && let Some(selection) = current_ranges.first()
 9837                {
 9838                    self.show_snippet_choices(choices, selection.clone(), cx);
 9839                }
 9840
 9841                // If snippet state is not at the last tabstop, push it back on the stack
 9842                if snippet.active_index + 1 < snippet.ranges.len() {
 9843                    self.snippet_stack.push(snippet);
 9844                }
 9845                return true;
 9846            }
 9847        }
 9848
 9849        false
 9850    }
 9851
 9852    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9853        self.transact(window, cx, |this, window, cx| {
 9854            this.select_all(&SelectAll, window, cx);
 9855            this.insert("", window, cx);
 9856        });
 9857    }
 9858
 9859    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9860        if self.read_only(cx) {
 9861            return;
 9862        }
 9863        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9864        self.transact(window, cx, |this, window, cx| {
 9865            this.select_autoclose_pair(window, cx);
 9866            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9867            if !this.linked_edit_ranges.is_empty() {
 9868                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9869                let snapshot = this.buffer.read(cx).snapshot(cx);
 9870
 9871                for selection in selections.iter() {
 9872                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9873                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9874                    if selection_start.buffer_id != selection_end.buffer_id {
 9875                        continue;
 9876                    }
 9877                    if let Some(ranges) =
 9878                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9879                    {
 9880                        for (buffer, entries) in ranges {
 9881                            linked_ranges.entry(buffer).or_default().extend(entries);
 9882                        }
 9883                    }
 9884                }
 9885            }
 9886
 9887            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9888            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9889            for selection in &mut selections {
 9890                if selection.is_empty() {
 9891                    let old_head = selection.head();
 9892                    let mut new_head =
 9893                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9894                            .to_point(&display_map);
 9895                    if let Some((buffer, line_buffer_range)) = display_map
 9896                        .buffer_snapshot
 9897                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9898                    {
 9899                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9900                        let indent_len = match indent_size.kind {
 9901                            IndentKind::Space => {
 9902                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9903                            }
 9904                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9905                        };
 9906                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9907                            let indent_len = indent_len.get();
 9908                            new_head = cmp::min(
 9909                                new_head,
 9910                                MultiBufferPoint::new(
 9911                                    old_head.row,
 9912                                    ((old_head.column - 1) / indent_len) * indent_len,
 9913                                ),
 9914                            );
 9915                        }
 9916                    }
 9917
 9918                    selection.set_head(new_head, SelectionGoal::None);
 9919                }
 9920            }
 9921
 9922            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9923            this.insert("", window, cx);
 9924            let empty_str: Arc<str> = Arc::from("");
 9925            for (buffer, edits) in linked_ranges {
 9926                let snapshot = buffer.read(cx).snapshot();
 9927                use text::ToPoint as TP;
 9928
 9929                let edits = edits
 9930                    .into_iter()
 9931                    .map(|range| {
 9932                        let end_point = TP::to_point(&range.end, &snapshot);
 9933                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9934
 9935                        if end_point == start_point {
 9936                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9937                                .saturating_sub(1);
 9938                            start_point =
 9939                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9940                        };
 9941
 9942                        (start_point..end_point, empty_str.clone())
 9943                    })
 9944                    .sorted_by_key(|(range, _)| range.start)
 9945                    .collect::<Vec<_>>();
 9946                buffer.update(cx, |this, cx| {
 9947                    this.edit(edits, None, cx);
 9948                })
 9949            }
 9950            this.refresh_edit_prediction(true, false, window, cx);
 9951            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9952        });
 9953    }
 9954
 9955    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9956        if self.read_only(cx) {
 9957            return;
 9958        }
 9959        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9960        self.transact(window, cx, |this, window, cx| {
 9961            this.change_selections(Default::default(), window, cx, |s| {
 9962                s.move_with(|map, selection| {
 9963                    if selection.is_empty() {
 9964                        let cursor = movement::right(map, selection.head());
 9965                        selection.end = cursor;
 9966                        selection.reversed = true;
 9967                        selection.goal = SelectionGoal::None;
 9968                    }
 9969                })
 9970            });
 9971            this.insert("", window, cx);
 9972            this.refresh_edit_prediction(true, false, window, cx);
 9973        });
 9974    }
 9975
 9976    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9977        if self.mode.is_single_line() {
 9978            cx.propagate();
 9979            return;
 9980        }
 9981
 9982        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9983        if self.move_to_prev_snippet_tabstop(window, cx) {
 9984            return;
 9985        }
 9986        self.outdent(&Outdent, window, cx);
 9987    }
 9988
 9989    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9990        if self.mode.is_single_line() {
 9991            cx.propagate();
 9992            return;
 9993        }
 9994
 9995        if self.move_to_next_snippet_tabstop(window, cx) {
 9996            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9997            return;
 9998        }
 9999        if self.read_only(cx) {
10000            return;
10001        }
10002        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10003        let mut selections = self.selections.all_adjusted(cx);
10004        let buffer = self.buffer.read(cx);
10005        let snapshot = buffer.snapshot(cx);
10006        let rows_iter = selections.iter().map(|s| s.head().row);
10007        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10008
10009        let has_some_cursor_in_whitespace = selections
10010            .iter()
10011            .filter(|selection| selection.is_empty())
10012            .any(|selection| {
10013                let cursor = selection.head();
10014                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10015                cursor.column < current_indent.len
10016            });
10017
10018        let mut edits = Vec::new();
10019        let mut prev_edited_row = 0;
10020        let mut row_delta = 0;
10021        for selection in &mut selections {
10022            if selection.start.row != prev_edited_row {
10023                row_delta = 0;
10024            }
10025            prev_edited_row = selection.end.row;
10026
10027            // If the selection is non-empty, then increase the indentation of the selected lines.
10028            if !selection.is_empty() {
10029                row_delta =
10030                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10031                continue;
10032            }
10033
10034            let cursor = selection.head();
10035            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10036            if let Some(suggested_indent) =
10037                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10038            {
10039                // Don't do anything if already at suggested indent
10040                // and there is any other cursor which is not
10041                if has_some_cursor_in_whitespace
10042                    && cursor.column == current_indent.len
10043                    && current_indent.len == suggested_indent.len
10044                {
10045                    continue;
10046                }
10047
10048                // Adjust line and move cursor to suggested indent
10049                // if cursor is not at suggested indent
10050                if cursor.column < suggested_indent.len
10051                    && cursor.column <= current_indent.len
10052                    && current_indent.len <= suggested_indent.len
10053                {
10054                    selection.start = Point::new(cursor.row, suggested_indent.len);
10055                    selection.end = selection.start;
10056                    if row_delta == 0 {
10057                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10058                            cursor.row,
10059                            current_indent,
10060                            suggested_indent,
10061                        ));
10062                        row_delta = suggested_indent.len - current_indent.len;
10063                    }
10064                    continue;
10065                }
10066
10067                // If current indent is more than suggested indent
10068                // only move cursor to current indent and skip indent
10069                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10070                    selection.start = Point::new(cursor.row, current_indent.len);
10071                    selection.end = selection.start;
10072                    continue;
10073                }
10074            }
10075
10076            // Otherwise, insert a hard or soft tab.
10077            let settings = buffer.language_settings_at(cursor, cx);
10078            let tab_size = if settings.hard_tabs {
10079                IndentSize::tab()
10080            } else {
10081                let tab_size = settings.tab_size.get();
10082                let indent_remainder = snapshot
10083                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10084                    .flat_map(str::chars)
10085                    .fold(row_delta % tab_size, |counter: u32, c| {
10086                        if c == '\t' {
10087                            0
10088                        } else {
10089                            (counter + 1) % tab_size
10090                        }
10091                    });
10092
10093                let chars_to_next_tab_stop = tab_size - indent_remainder;
10094                IndentSize::spaces(chars_to_next_tab_stop)
10095            };
10096            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10097            selection.end = selection.start;
10098            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10099            row_delta += tab_size.len;
10100        }
10101
10102        self.transact(window, cx, |this, window, cx| {
10103            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10104            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10105            this.refresh_edit_prediction(true, false, window, cx);
10106        });
10107    }
10108
10109    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10110        if self.read_only(cx) {
10111            return;
10112        }
10113        if self.mode.is_single_line() {
10114            cx.propagate();
10115            return;
10116        }
10117
10118        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10119        let mut selections = self.selections.all::<Point>(cx);
10120        let mut prev_edited_row = 0;
10121        let mut row_delta = 0;
10122        let mut edits = Vec::new();
10123        let buffer = self.buffer.read(cx);
10124        let snapshot = buffer.snapshot(cx);
10125        for selection in &mut selections {
10126            if selection.start.row != prev_edited_row {
10127                row_delta = 0;
10128            }
10129            prev_edited_row = selection.end.row;
10130
10131            row_delta =
10132                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10133        }
10134
10135        self.transact(window, cx, |this, window, cx| {
10136            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10137            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10138        });
10139    }
10140
10141    fn indent_selection(
10142        buffer: &MultiBuffer,
10143        snapshot: &MultiBufferSnapshot,
10144        selection: &mut Selection<Point>,
10145        edits: &mut Vec<(Range<Point>, String)>,
10146        delta_for_start_row: u32,
10147        cx: &App,
10148    ) -> u32 {
10149        let settings = buffer.language_settings_at(selection.start, cx);
10150        let tab_size = settings.tab_size.get();
10151        let indent_kind = if settings.hard_tabs {
10152            IndentKind::Tab
10153        } else {
10154            IndentKind::Space
10155        };
10156        let mut start_row = selection.start.row;
10157        let mut end_row = selection.end.row + 1;
10158
10159        // If a selection ends at the beginning of a line, don't indent
10160        // that last line.
10161        if selection.end.column == 0 && selection.end.row > selection.start.row {
10162            end_row -= 1;
10163        }
10164
10165        // Avoid re-indenting a row that has already been indented by a
10166        // previous selection, but still update this selection's column
10167        // to reflect that indentation.
10168        if delta_for_start_row > 0 {
10169            start_row += 1;
10170            selection.start.column += delta_for_start_row;
10171            if selection.end.row == selection.start.row {
10172                selection.end.column += delta_for_start_row;
10173            }
10174        }
10175
10176        let mut delta_for_end_row = 0;
10177        let has_multiple_rows = start_row + 1 != end_row;
10178        for row in start_row..end_row {
10179            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10180            let indent_delta = match (current_indent.kind, indent_kind) {
10181                (IndentKind::Space, IndentKind::Space) => {
10182                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10183                    IndentSize::spaces(columns_to_next_tab_stop)
10184                }
10185                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10186                (_, IndentKind::Tab) => IndentSize::tab(),
10187            };
10188
10189            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10190                0
10191            } else {
10192                selection.start.column
10193            };
10194            let row_start = Point::new(row, start);
10195            edits.push((
10196                row_start..row_start,
10197                indent_delta.chars().collect::<String>(),
10198            ));
10199
10200            // Update this selection's endpoints to reflect the indentation.
10201            if row == selection.start.row {
10202                selection.start.column += indent_delta.len;
10203            }
10204            if row == selection.end.row {
10205                selection.end.column += indent_delta.len;
10206                delta_for_end_row = indent_delta.len;
10207            }
10208        }
10209
10210        if selection.start.row == selection.end.row {
10211            delta_for_start_row + delta_for_end_row
10212        } else {
10213            delta_for_end_row
10214        }
10215    }
10216
10217    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10218        if self.read_only(cx) {
10219            return;
10220        }
10221        if self.mode.is_single_line() {
10222            cx.propagate();
10223            return;
10224        }
10225
10226        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10227        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10228        let selections = self.selections.all::<Point>(cx);
10229        let mut deletion_ranges = Vec::new();
10230        let mut last_outdent = None;
10231        {
10232            let buffer = self.buffer.read(cx);
10233            let snapshot = buffer.snapshot(cx);
10234            for selection in &selections {
10235                let settings = buffer.language_settings_at(selection.start, cx);
10236                let tab_size = settings.tab_size.get();
10237                let mut rows = selection.spanned_rows(false, &display_map);
10238
10239                // Avoid re-outdenting a row that has already been outdented by a
10240                // previous selection.
10241                if let Some(last_row) = last_outdent
10242                    && last_row == rows.start
10243                {
10244                    rows.start = rows.start.next_row();
10245                }
10246                let has_multiple_rows = rows.len() > 1;
10247                for row in rows.iter_rows() {
10248                    let indent_size = snapshot.indent_size_for_line(row);
10249                    if indent_size.len > 0 {
10250                        let deletion_len = match indent_size.kind {
10251                            IndentKind::Space => {
10252                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10253                                if columns_to_prev_tab_stop == 0 {
10254                                    tab_size
10255                                } else {
10256                                    columns_to_prev_tab_stop
10257                                }
10258                            }
10259                            IndentKind::Tab => 1,
10260                        };
10261                        let start = if has_multiple_rows
10262                            || deletion_len > selection.start.column
10263                            || indent_size.len < selection.start.column
10264                        {
10265                            0
10266                        } else {
10267                            selection.start.column - deletion_len
10268                        };
10269                        deletion_ranges.push(
10270                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10271                        );
10272                        last_outdent = Some(row);
10273                    }
10274                }
10275            }
10276        }
10277
10278        self.transact(window, cx, |this, window, cx| {
10279            this.buffer.update(cx, |buffer, cx| {
10280                let empty_str: Arc<str> = Arc::default();
10281                buffer.edit(
10282                    deletion_ranges
10283                        .into_iter()
10284                        .map(|range| (range, empty_str.clone())),
10285                    None,
10286                    cx,
10287                );
10288            });
10289            let selections = this.selections.all::<usize>(cx);
10290            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10291        });
10292    }
10293
10294    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10295        if self.read_only(cx) {
10296            return;
10297        }
10298        if self.mode.is_single_line() {
10299            cx.propagate();
10300            return;
10301        }
10302
10303        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10304        let selections = self
10305            .selections
10306            .all::<usize>(cx)
10307            .into_iter()
10308            .map(|s| s.range());
10309
10310        self.transact(window, cx, |this, window, cx| {
10311            this.buffer.update(cx, |buffer, cx| {
10312                buffer.autoindent_ranges(selections, cx);
10313            });
10314            let selections = this.selections.all::<usize>(cx);
10315            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10316        });
10317    }
10318
10319    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10320        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10321        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10322        let selections = self.selections.all::<Point>(cx);
10323
10324        let mut new_cursors = Vec::new();
10325        let mut edit_ranges = Vec::new();
10326        let mut selections = selections.iter().peekable();
10327        while let Some(selection) = selections.next() {
10328            let mut rows = selection.spanned_rows(false, &display_map);
10329            let goal_display_column = selection.head().to_display_point(&display_map).column();
10330
10331            // Accumulate contiguous regions of rows that we want to delete.
10332            while let Some(next_selection) = selections.peek() {
10333                let next_rows = next_selection.spanned_rows(false, &display_map);
10334                if next_rows.start <= rows.end {
10335                    rows.end = next_rows.end;
10336                    selections.next().unwrap();
10337                } else {
10338                    break;
10339                }
10340            }
10341
10342            let buffer = &display_map.buffer_snapshot;
10343            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10344            let edit_end;
10345            let cursor_buffer_row;
10346            if buffer.max_point().row >= rows.end.0 {
10347                // If there's a line after the range, delete the \n from the end of the row range
10348                // and position the cursor on the next line.
10349                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10350                cursor_buffer_row = rows.end;
10351            } else {
10352                // If there isn't a line after the range, delete the \n from the line before the
10353                // start of the row range and position the cursor there.
10354                edit_start = edit_start.saturating_sub(1);
10355                edit_end = buffer.len();
10356                cursor_buffer_row = rows.start.previous_row();
10357            }
10358
10359            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10360            *cursor.column_mut() =
10361                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10362
10363            new_cursors.push((
10364                selection.id,
10365                buffer.anchor_after(cursor.to_point(&display_map)),
10366            ));
10367            edit_ranges.push(edit_start..edit_end);
10368        }
10369
10370        self.transact(window, cx, |this, window, cx| {
10371            let buffer = this.buffer.update(cx, |buffer, cx| {
10372                let empty_str: Arc<str> = Arc::default();
10373                buffer.edit(
10374                    edit_ranges
10375                        .into_iter()
10376                        .map(|range| (range, empty_str.clone())),
10377                    None,
10378                    cx,
10379                );
10380                buffer.snapshot(cx)
10381            });
10382            let new_selections = new_cursors
10383                .into_iter()
10384                .map(|(id, cursor)| {
10385                    let cursor = cursor.to_point(&buffer);
10386                    Selection {
10387                        id,
10388                        start: cursor,
10389                        end: cursor,
10390                        reversed: false,
10391                        goal: SelectionGoal::None,
10392                    }
10393                })
10394                .collect();
10395
10396            this.change_selections(Default::default(), window, cx, |s| {
10397                s.select(new_selections);
10398            });
10399        });
10400    }
10401
10402    pub fn join_lines_impl(
10403        &mut self,
10404        insert_whitespace: bool,
10405        window: &mut Window,
10406        cx: &mut Context<Self>,
10407    ) {
10408        if self.read_only(cx) {
10409            return;
10410        }
10411        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10412        for selection in self.selections.all::<Point>(cx) {
10413            let start = MultiBufferRow(selection.start.row);
10414            // Treat single line selections as if they include the next line. Otherwise this action
10415            // would do nothing for single line selections individual cursors.
10416            let end = if selection.start.row == selection.end.row {
10417                MultiBufferRow(selection.start.row + 1)
10418            } else {
10419                MultiBufferRow(selection.end.row)
10420            };
10421
10422            if let Some(last_row_range) = row_ranges.last_mut()
10423                && start <= last_row_range.end
10424            {
10425                last_row_range.end = end;
10426                continue;
10427            }
10428            row_ranges.push(start..end);
10429        }
10430
10431        let snapshot = self.buffer.read(cx).snapshot(cx);
10432        let mut cursor_positions = Vec::new();
10433        for row_range in &row_ranges {
10434            let anchor = snapshot.anchor_before(Point::new(
10435                row_range.end.previous_row().0,
10436                snapshot.line_len(row_range.end.previous_row()),
10437            ));
10438            cursor_positions.push(anchor..anchor);
10439        }
10440
10441        self.transact(window, cx, |this, window, cx| {
10442            for row_range in row_ranges.into_iter().rev() {
10443                for row in row_range.iter_rows().rev() {
10444                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10445                    let next_line_row = row.next_row();
10446                    let indent = snapshot.indent_size_for_line(next_line_row);
10447                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10448
10449                    let replace =
10450                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10451                            " "
10452                        } else {
10453                            ""
10454                        };
10455
10456                    this.buffer.update(cx, |buffer, cx| {
10457                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10458                    });
10459                }
10460            }
10461
10462            this.change_selections(Default::default(), window, cx, |s| {
10463                s.select_anchor_ranges(cursor_positions)
10464            });
10465        });
10466    }
10467
10468    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10469        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10470        self.join_lines_impl(true, window, cx);
10471    }
10472
10473    pub fn sort_lines_case_sensitive(
10474        &mut self,
10475        _: &SortLinesCaseSensitive,
10476        window: &mut Window,
10477        cx: &mut Context<Self>,
10478    ) {
10479        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10480    }
10481
10482    pub fn sort_lines_by_length(
10483        &mut self,
10484        _: &SortLinesByLength,
10485        window: &mut Window,
10486        cx: &mut Context<Self>,
10487    ) {
10488        self.manipulate_immutable_lines(window, cx, |lines| {
10489            lines.sort_by_key(|&line| line.chars().count())
10490        })
10491    }
10492
10493    pub fn sort_lines_case_insensitive(
10494        &mut self,
10495        _: &SortLinesCaseInsensitive,
10496        window: &mut Window,
10497        cx: &mut Context<Self>,
10498    ) {
10499        self.manipulate_immutable_lines(window, cx, |lines| {
10500            lines.sort_by_key(|line| line.to_lowercase())
10501        })
10502    }
10503
10504    pub fn unique_lines_case_insensitive(
10505        &mut self,
10506        _: &UniqueLinesCaseInsensitive,
10507        window: &mut Window,
10508        cx: &mut Context<Self>,
10509    ) {
10510        self.manipulate_immutable_lines(window, cx, |lines| {
10511            let mut seen = HashSet::default();
10512            lines.retain(|line| seen.insert(line.to_lowercase()));
10513        })
10514    }
10515
10516    pub fn unique_lines_case_sensitive(
10517        &mut self,
10518        _: &UniqueLinesCaseSensitive,
10519        window: &mut Window,
10520        cx: &mut Context<Self>,
10521    ) {
10522        self.manipulate_immutable_lines(window, cx, |lines| {
10523            let mut seen = HashSet::default();
10524            lines.retain(|line| seen.insert(*line));
10525        })
10526    }
10527
10528    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10529        let snapshot = self.buffer.read(cx).snapshot(cx);
10530        for selection in self.selections.disjoint_anchors_arc().iter() {
10531            if snapshot
10532                .language_at(selection.start)
10533                .and_then(|lang| lang.config().wrap_characters.as_ref())
10534                .is_some()
10535            {
10536                return true;
10537            }
10538        }
10539        false
10540    }
10541
10542    fn wrap_selections_in_tag(
10543        &mut self,
10544        _: &WrapSelectionsInTag,
10545        window: &mut Window,
10546        cx: &mut Context<Self>,
10547    ) {
10548        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10549
10550        let snapshot = self.buffer.read(cx).snapshot(cx);
10551
10552        let mut edits = Vec::new();
10553        let mut boundaries = Vec::new();
10554
10555        for selection in self.selections.all::<Point>(cx).iter() {
10556            let Some(wrap_config) = snapshot
10557                .language_at(selection.start)
10558                .and_then(|lang| lang.config().wrap_characters.clone())
10559            else {
10560                continue;
10561            };
10562
10563            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10564            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10565
10566            let start_before = snapshot.anchor_before(selection.start);
10567            let end_after = snapshot.anchor_after(selection.end);
10568
10569            edits.push((start_before..start_before, open_tag));
10570            edits.push((end_after..end_after, close_tag));
10571
10572            boundaries.push((
10573                start_before,
10574                end_after,
10575                wrap_config.start_prefix.len(),
10576                wrap_config.end_suffix.len(),
10577            ));
10578        }
10579
10580        if edits.is_empty() {
10581            return;
10582        }
10583
10584        self.transact(window, cx, |this, window, cx| {
10585            let buffer = this.buffer.update(cx, |buffer, cx| {
10586                buffer.edit(edits, None, cx);
10587                buffer.snapshot(cx)
10588            });
10589
10590            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10591            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10592                boundaries.into_iter()
10593            {
10594                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10595                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10596                new_selections.push(open_offset..open_offset);
10597                new_selections.push(close_offset..close_offset);
10598            }
10599
10600            this.change_selections(Default::default(), window, cx, |s| {
10601                s.select_ranges(new_selections);
10602            });
10603
10604            this.request_autoscroll(Autoscroll::fit(), cx);
10605        });
10606    }
10607
10608    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10609        let Some(project) = self.project.clone() else {
10610            return;
10611        };
10612        self.reload(project, window, cx)
10613            .detach_and_notify_err(window, cx);
10614    }
10615
10616    pub fn restore_file(
10617        &mut self,
10618        _: &::git::RestoreFile,
10619        window: &mut Window,
10620        cx: &mut Context<Self>,
10621    ) {
10622        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10623        let mut buffer_ids = HashSet::default();
10624        let snapshot = self.buffer().read(cx).snapshot(cx);
10625        for selection in self.selections.all::<usize>(cx) {
10626            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10627        }
10628
10629        let buffer = self.buffer().read(cx);
10630        let ranges = buffer_ids
10631            .into_iter()
10632            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10633            .collect::<Vec<_>>();
10634
10635        self.restore_hunks_in_ranges(ranges, window, cx);
10636    }
10637
10638    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10639        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10640        let selections = self
10641            .selections
10642            .all(cx)
10643            .into_iter()
10644            .map(|s| s.range())
10645            .collect();
10646        self.restore_hunks_in_ranges(selections, window, cx);
10647    }
10648
10649    pub fn restore_hunks_in_ranges(
10650        &mut self,
10651        ranges: Vec<Range<Point>>,
10652        window: &mut Window,
10653        cx: &mut Context<Editor>,
10654    ) {
10655        let mut revert_changes = HashMap::default();
10656        let chunk_by = self
10657            .snapshot(window, cx)
10658            .hunks_for_ranges(ranges)
10659            .into_iter()
10660            .chunk_by(|hunk| hunk.buffer_id);
10661        for (buffer_id, hunks) in &chunk_by {
10662            let hunks = hunks.collect::<Vec<_>>();
10663            for hunk in &hunks {
10664                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10665            }
10666            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10667        }
10668        drop(chunk_by);
10669        if !revert_changes.is_empty() {
10670            self.transact(window, cx, |editor, window, cx| {
10671                editor.restore(revert_changes, window, cx);
10672            });
10673        }
10674    }
10675
10676    pub fn open_active_item_in_terminal(
10677        &mut self,
10678        _: &OpenInTerminal,
10679        window: &mut Window,
10680        cx: &mut Context<Self>,
10681    ) {
10682        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10683            let project_path = buffer.read(cx).project_path(cx)?;
10684            let project = self.project()?.read(cx);
10685            let entry = project.entry_for_path(&project_path, cx)?;
10686            let parent = match &entry.canonical_path {
10687                Some(canonical_path) => canonical_path.to_path_buf(),
10688                None => project.absolute_path(&project_path, cx)?,
10689            }
10690            .parent()?
10691            .to_path_buf();
10692            Some(parent)
10693        }) {
10694            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10695        }
10696    }
10697
10698    fn set_breakpoint_context_menu(
10699        &mut self,
10700        display_row: DisplayRow,
10701        position: Option<Anchor>,
10702        clicked_point: gpui::Point<Pixels>,
10703        window: &mut Window,
10704        cx: &mut Context<Self>,
10705    ) {
10706        let source = self
10707            .buffer
10708            .read(cx)
10709            .snapshot(cx)
10710            .anchor_before(Point::new(display_row.0, 0u32));
10711
10712        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10713
10714        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10715            self,
10716            source,
10717            clicked_point,
10718            context_menu,
10719            window,
10720            cx,
10721        );
10722    }
10723
10724    fn add_edit_breakpoint_block(
10725        &mut self,
10726        anchor: Anchor,
10727        breakpoint: &Breakpoint,
10728        edit_action: BreakpointPromptEditAction,
10729        window: &mut Window,
10730        cx: &mut Context<Self>,
10731    ) {
10732        let weak_editor = cx.weak_entity();
10733        let bp_prompt = cx.new(|cx| {
10734            BreakpointPromptEditor::new(
10735                weak_editor,
10736                anchor,
10737                breakpoint.clone(),
10738                edit_action,
10739                window,
10740                cx,
10741            )
10742        });
10743
10744        let height = bp_prompt.update(cx, |this, cx| {
10745            this.prompt
10746                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10747        });
10748        let cloned_prompt = bp_prompt.clone();
10749        let blocks = vec![BlockProperties {
10750            style: BlockStyle::Sticky,
10751            placement: BlockPlacement::Above(anchor),
10752            height: Some(height),
10753            render: Arc::new(move |cx| {
10754                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10755                cloned_prompt.clone().into_any_element()
10756            }),
10757            priority: 0,
10758        }];
10759
10760        let focus_handle = bp_prompt.focus_handle(cx);
10761        window.focus(&focus_handle);
10762
10763        let block_ids = self.insert_blocks(blocks, None, cx);
10764        bp_prompt.update(cx, |prompt, _| {
10765            prompt.add_block_ids(block_ids);
10766        });
10767    }
10768
10769    pub(crate) fn breakpoint_at_row(
10770        &self,
10771        row: u32,
10772        window: &mut Window,
10773        cx: &mut Context<Self>,
10774    ) -> Option<(Anchor, Breakpoint)> {
10775        let snapshot = self.snapshot(window, cx);
10776        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10777
10778        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10779    }
10780
10781    pub(crate) fn breakpoint_at_anchor(
10782        &self,
10783        breakpoint_position: Anchor,
10784        snapshot: &EditorSnapshot,
10785        cx: &mut Context<Self>,
10786    ) -> Option<(Anchor, Breakpoint)> {
10787        let buffer = self
10788            .buffer
10789            .read(cx)
10790            .buffer_for_anchor(breakpoint_position, cx)?;
10791
10792        let enclosing_excerpt = breakpoint_position.excerpt_id;
10793        let buffer_snapshot = buffer.read(cx).snapshot();
10794
10795        let row = buffer_snapshot
10796            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10797            .row;
10798
10799        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10800        let anchor_end = snapshot
10801            .buffer_snapshot
10802            .anchor_after(Point::new(row, line_len));
10803
10804        self.breakpoint_store
10805            .as_ref()?
10806            .read_with(cx, |breakpoint_store, cx| {
10807                breakpoint_store
10808                    .breakpoints(
10809                        &buffer,
10810                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10811                        &buffer_snapshot,
10812                        cx,
10813                    )
10814                    .next()
10815                    .and_then(|(bp, _)| {
10816                        let breakpoint_row = buffer_snapshot
10817                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10818                            .row;
10819
10820                        if breakpoint_row == row {
10821                            snapshot
10822                                .buffer_snapshot
10823                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10824                                .map(|position| (position, bp.bp.clone()))
10825                        } else {
10826                            None
10827                        }
10828                    })
10829            })
10830    }
10831
10832    pub fn edit_log_breakpoint(
10833        &mut self,
10834        _: &EditLogBreakpoint,
10835        window: &mut Window,
10836        cx: &mut Context<Self>,
10837    ) {
10838        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10839            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10840                message: None,
10841                state: BreakpointState::Enabled,
10842                condition: None,
10843                hit_condition: None,
10844            });
10845
10846            self.add_edit_breakpoint_block(
10847                anchor,
10848                &breakpoint,
10849                BreakpointPromptEditAction::Log,
10850                window,
10851                cx,
10852            );
10853        }
10854    }
10855
10856    fn breakpoints_at_cursors(
10857        &self,
10858        window: &mut Window,
10859        cx: &mut Context<Self>,
10860    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10861        let snapshot = self.snapshot(window, cx);
10862        let cursors = self
10863            .selections
10864            .disjoint_anchors_arc()
10865            .iter()
10866            .map(|selection| {
10867                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10868
10869                let breakpoint_position = self
10870                    .breakpoint_at_row(cursor_position.row, window, cx)
10871                    .map(|bp| bp.0)
10872                    .unwrap_or_else(|| {
10873                        snapshot
10874                            .display_snapshot
10875                            .buffer_snapshot
10876                            .anchor_after(Point::new(cursor_position.row, 0))
10877                    });
10878
10879                let breakpoint = self
10880                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10881                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10882
10883                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10884            })
10885            // 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.
10886            .collect::<HashMap<Anchor, _>>();
10887
10888        cursors.into_iter().collect()
10889    }
10890
10891    pub fn enable_breakpoint(
10892        &mut self,
10893        _: &crate::actions::EnableBreakpoint,
10894        window: &mut Window,
10895        cx: &mut Context<Self>,
10896    ) {
10897        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10898            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10899                continue;
10900            };
10901            self.edit_breakpoint_at_anchor(
10902                anchor,
10903                breakpoint,
10904                BreakpointEditAction::InvertState,
10905                cx,
10906            );
10907        }
10908    }
10909
10910    pub fn disable_breakpoint(
10911        &mut self,
10912        _: &crate::actions::DisableBreakpoint,
10913        window: &mut Window,
10914        cx: &mut Context<Self>,
10915    ) {
10916        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10917            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10918                continue;
10919            };
10920            self.edit_breakpoint_at_anchor(
10921                anchor,
10922                breakpoint,
10923                BreakpointEditAction::InvertState,
10924                cx,
10925            );
10926        }
10927    }
10928
10929    pub fn toggle_breakpoint(
10930        &mut self,
10931        _: &crate::actions::ToggleBreakpoint,
10932        window: &mut Window,
10933        cx: &mut Context<Self>,
10934    ) {
10935        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10936            if let Some(breakpoint) = breakpoint {
10937                self.edit_breakpoint_at_anchor(
10938                    anchor,
10939                    breakpoint,
10940                    BreakpointEditAction::Toggle,
10941                    cx,
10942                );
10943            } else {
10944                self.edit_breakpoint_at_anchor(
10945                    anchor,
10946                    Breakpoint::new_standard(),
10947                    BreakpointEditAction::Toggle,
10948                    cx,
10949                );
10950            }
10951        }
10952    }
10953
10954    pub fn edit_breakpoint_at_anchor(
10955        &mut self,
10956        breakpoint_position: Anchor,
10957        breakpoint: Breakpoint,
10958        edit_action: BreakpointEditAction,
10959        cx: &mut Context<Self>,
10960    ) {
10961        let Some(breakpoint_store) = &self.breakpoint_store else {
10962            return;
10963        };
10964
10965        let Some(buffer) = self
10966            .buffer
10967            .read(cx)
10968            .buffer_for_anchor(breakpoint_position, cx)
10969        else {
10970            return;
10971        };
10972
10973        breakpoint_store.update(cx, |breakpoint_store, cx| {
10974            breakpoint_store.toggle_breakpoint(
10975                buffer,
10976                BreakpointWithPosition {
10977                    position: breakpoint_position.text_anchor,
10978                    bp: breakpoint,
10979                },
10980                edit_action,
10981                cx,
10982            );
10983        });
10984
10985        cx.notify();
10986    }
10987
10988    #[cfg(any(test, feature = "test-support"))]
10989    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10990        self.breakpoint_store.clone()
10991    }
10992
10993    pub fn prepare_restore_change(
10994        &self,
10995        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10996        hunk: &MultiBufferDiffHunk,
10997        cx: &mut App,
10998    ) -> Option<()> {
10999        if hunk.is_created_file() {
11000            return None;
11001        }
11002        let buffer = self.buffer.read(cx);
11003        let diff = buffer.diff_for(hunk.buffer_id)?;
11004        let buffer = buffer.buffer(hunk.buffer_id)?;
11005        let buffer = buffer.read(cx);
11006        let original_text = diff
11007            .read(cx)
11008            .base_text()
11009            .as_rope()
11010            .slice(hunk.diff_base_byte_range.clone());
11011        let buffer_snapshot = buffer.snapshot();
11012        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11013        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11014            probe
11015                .0
11016                .start
11017                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11018                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11019        }) {
11020            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11021            Some(())
11022        } else {
11023            None
11024        }
11025    }
11026
11027    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11028        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11029    }
11030
11031    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11032        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11033    }
11034
11035    fn manipulate_lines<M>(
11036        &mut self,
11037        window: &mut Window,
11038        cx: &mut Context<Self>,
11039        mut manipulate: M,
11040    ) where
11041        M: FnMut(&str) -> LineManipulationResult,
11042    {
11043        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11044
11045        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11046        let buffer = self.buffer.read(cx).snapshot(cx);
11047
11048        let mut edits = Vec::new();
11049
11050        let selections = self.selections.all::<Point>(cx);
11051        let mut selections = selections.iter().peekable();
11052        let mut contiguous_row_selections = Vec::new();
11053        let mut new_selections = Vec::new();
11054        let mut added_lines = 0;
11055        let mut removed_lines = 0;
11056
11057        while let Some(selection) = selections.next() {
11058            let (start_row, end_row) = consume_contiguous_rows(
11059                &mut contiguous_row_selections,
11060                selection,
11061                &display_map,
11062                &mut selections,
11063            );
11064
11065            let start_point = Point::new(start_row.0, 0);
11066            let end_point = Point::new(
11067                end_row.previous_row().0,
11068                buffer.line_len(end_row.previous_row()),
11069            );
11070            let text = buffer
11071                .text_for_range(start_point..end_point)
11072                .collect::<String>();
11073
11074            let LineManipulationResult {
11075                new_text,
11076                line_count_before,
11077                line_count_after,
11078            } = manipulate(&text);
11079
11080            edits.push((start_point..end_point, new_text));
11081
11082            // Selections must change based on added and removed line count
11083            let start_row =
11084                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11085            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11086            new_selections.push(Selection {
11087                id: selection.id,
11088                start: start_row,
11089                end: end_row,
11090                goal: SelectionGoal::None,
11091                reversed: selection.reversed,
11092            });
11093
11094            if line_count_after > line_count_before {
11095                added_lines += line_count_after - line_count_before;
11096            } else if line_count_before > line_count_after {
11097                removed_lines += line_count_before - line_count_after;
11098            }
11099        }
11100
11101        self.transact(window, cx, |this, window, cx| {
11102            let buffer = this.buffer.update(cx, |buffer, cx| {
11103                buffer.edit(edits, None, cx);
11104                buffer.snapshot(cx)
11105            });
11106
11107            // Recalculate offsets on newly edited buffer
11108            let new_selections = new_selections
11109                .iter()
11110                .map(|s| {
11111                    let start_point = Point::new(s.start.0, 0);
11112                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11113                    Selection {
11114                        id: s.id,
11115                        start: buffer.point_to_offset(start_point),
11116                        end: buffer.point_to_offset(end_point),
11117                        goal: s.goal,
11118                        reversed: s.reversed,
11119                    }
11120                })
11121                .collect();
11122
11123            this.change_selections(Default::default(), window, cx, |s| {
11124                s.select(new_selections);
11125            });
11126
11127            this.request_autoscroll(Autoscroll::fit(), cx);
11128        });
11129    }
11130
11131    fn manipulate_immutable_lines<Fn>(
11132        &mut self,
11133        window: &mut Window,
11134        cx: &mut Context<Self>,
11135        mut callback: Fn,
11136    ) where
11137        Fn: FnMut(&mut Vec<&str>),
11138    {
11139        self.manipulate_lines(window, cx, |text| {
11140            let mut lines: Vec<&str> = text.split('\n').collect();
11141            let line_count_before = lines.len();
11142
11143            callback(&mut lines);
11144
11145            LineManipulationResult {
11146                new_text: lines.join("\n"),
11147                line_count_before,
11148                line_count_after: lines.len(),
11149            }
11150        });
11151    }
11152
11153    fn manipulate_mutable_lines<Fn>(
11154        &mut self,
11155        window: &mut Window,
11156        cx: &mut Context<Self>,
11157        mut callback: Fn,
11158    ) where
11159        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11160    {
11161        self.manipulate_lines(window, cx, |text| {
11162            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11163            let line_count_before = lines.len();
11164
11165            callback(&mut lines);
11166
11167            LineManipulationResult {
11168                new_text: lines.join("\n"),
11169                line_count_before,
11170                line_count_after: lines.len(),
11171            }
11172        });
11173    }
11174
11175    pub fn convert_indentation_to_spaces(
11176        &mut self,
11177        _: &ConvertIndentationToSpaces,
11178        window: &mut Window,
11179        cx: &mut Context<Self>,
11180    ) {
11181        let settings = self.buffer.read(cx).language_settings(cx);
11182        let tab_size = settings.tab_size.get() as usize;
11183
11184        self.manipulate_mutable_lines(window, cx, |lines| {
11185            // Allocates a reasonably sized scratch buffer once for the whole loop
11186            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11187            // Avoids recomputing spaces that could be inserted many times
11188            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11189                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11190                .collect();
11191
11192            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11193                let mut chars = line.as_ref().chars();
11194                let mut col = 0;
11195                let mut changed = false;
11196
11197                for ch in chars.by_ref() {
11198                    match ch {
11199                        ' ' => {
11200                            reindented_line.push(' ');
11201                            col += 1;
11202                        }
11203                        '\t' => {
11204                            // \t are converted to spaces depending on the current column
11205                            let spaces_len = tab_size - (col % tab_size);
11206                            reindented_line.extend(&space_cache[spaces_len - 1]);
11207                            col += spaces_len;
11208                            changed = true;
11209                        }
11210                        _ => {
11211                            // If we dont append before break, the character is consumed
11212                            reindented_line.push(ch);
11213                            break;
11214                        }
11215                    }
11216                }
11217
11218                if !changed {
11219                    reindented_line.clear();
11220                    continue;
11221                }
11222                // Append the rest of the line and replace old reference with new one
11223                reindented_line.extend(chars);
11224                *line = Cow::Owned(reindented_line.clone());
11225                reindented_line.clear();
11226            }
11227        });
11228    }
11229
11230    pub fn convert_indentation_to_tabs(
11231        &mut self,
11232        _: &ConvertIndentationToTabs,
11233        window: &mut Window,
11234        cx: &mut Context<Self>,
11235    ) {
11236        let settings = self.buffer.read(cx).language_settings(cx);
11237        let tab_size = settings.tab_size.get() as usize;
11238
11239        self.manipulate_mutable_lines(window, cx, |lines| {
11240            // Allocates a reasonably sized buffer once for the whole loop
11241            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11242            // Avoids recomputing spaces that could be inserted many times
11243            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11244                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11245                .collect();
11246
11247            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11248                let mut chars = line.chars();
11249                let mut spaces_count = 0;
11250                let mut first_non_indent_char = None;
11251                let mut changed = false;
11252
11253                for ch in chars.by_ref() {
11254                    match ch {
11255                        ' ' => {
11256                            // Keep track of spaces. Append \t when we reach tab_size
11257                            spaces_count += 1;
11258                            changed = true;
11259                            if spaces_count == tab_size {
11260                                reindented_line.push('\t');
11261                                spaces_count = 0;
11262                            }
11263                        }
11264                        '\t' => {
11265                            reindented_line.push('\t');
11266                            spaces_count = 0;
11267                        }
11268                        _ => {
11269                            // Dont append it yet, we might have remaining spaces
11270                            first_non_indent_char = Some(ch);
11271                            break;
11272                        }
11273                    }
11274                }
11275
11276                if !changed {
11277                    reindented_line.clear();
11278                    continue;
11279                }
11280                // Remaining spaces that didn't make a full tab stop
11281                if spaces_count > 0 {
11282                    reindented_line.extend(&space_cache[spaces_count - 1]);
11283                }
11284                // If we consume an extra character that was not indentation, add it back
11285                if let Some(extra_char) = first_non_indent_char {
11286                    reindented_line.push(extra_char);
11287                }
11288                // Append the rest of the line and replace old reference with new one
11289                reindented_line.extend(chars);
11290                *line = Cow::Owned(reindented_line.clone());
11291                reindented_line.clear();
11292            }
11293        });
11294    }
11295
11296    pub fn convert_to_upper_case(
11297        &mut self,
11298        _: &ConvertToUpperCase,
11299        window: &mut Window,
11300        cx: &mut Context<Self>,
11301    ) {
11302        self.manipulate_text(window, cx, |text| text.to_uppercase())
11303    }
11304
11305    pub fn convert_to_lower_case(
11306        &mut self,
11307        _: &ConvertToLowerCase,
11308        window: &mut Window,
11309        cx: &mut Context<Self>,
11310    ) {
11311        self.manipulate_text(window, cx, |text| text.to_lowercase())
11312    }
11313
11314    pub fn convert_to_title_case(
11315        &mut self,
11316        _: &ConvertToTitleCase,
11317        window: &mut Window,
11318        cx: &mut Context<Self>,
11319    ) {
11320        self.manipulate_text(window, cx, |text| {
11321            text.split('\n')
11322                .map(|line| line.to_case(Case::Title))
11323                .join("\n")
11324        })
11325    }
11326
11327    pub fn convert_to_snake_case(
11328        &mut self,
11329        _: &ConvertToSnakeCase,
11330        window: &mut Window,
11331        cx: &mut Context<Self>,
11332    ) {
11333        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11334    }
11335
11336    pub fn convert_to_kebab_case(
11337        &mut self,
11338        _: &ConvertToKebabCase,
11339        window: &mut Window,
11340        cx: &mut Context<Self>,
11341    ) {
11342        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11343    }
11344
11345    pub fn convert_to_upper_camel_case(
11346        &mut self,
11347        _: &ConvertToUpperCamelCase,
11348        window: &mut Window,
11349        cx: &mut Context<Self>,
11350    ) {
11351        self.manipulate_text(window, cx, |text| {
11352            text.split('\n')
11353                .map(|line| line.to_case(Case::UpperCamel))
11354                .join("\n")
11355        })
11356    }
11357
11358    pub fn convert_to_lower_camel_case(
11359        &mut self,
11360        _: &ConvertToLowerCamelCase,
11361        window: &mut Window,
11362        cx: &mut Context<Self>,
11363    ) {
11364        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11365    }
11366
11367    pub fn convert_to_opposite_case(
11368        &mut self,
11369        _: &ConvertToOppositeCase,
11370        window: &mut Window,
11371        cx: &mut Context<Self>,
11372    ) {
11373        self.manipulate_text(window, cx, |text| {
11374            text.chars()
11375                .fold(String::with_capacity(text.len()), |mut t, c| {
11376                    if c.is_uppercase() {
11377                        t.extend(c.to_lowercase());
11378                    } else {
11379                        t.extend(c.to_uppercase());
11380                    }
11381                    t
11382                })
11383        })
11384    }
11385
11386    pub fn convert_to_sentence_case(
11387        &mut self,
11388        _: &ConvertToSentenceCase,
11389        window: &mut Window,
11390        cx: &mut Context<Self>,
11391    ) {
11392        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11393    }
11394
11395    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11396        self.manipulate_text(window, cx, |text| {
11397            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11398            if has_upper_case_characters {
11399                text.to_lowercase()
11400            } else {
11401                text.to_uppercase()
11402            }
11403        })
11404    }
11405
11406    pub fn convert_to_rot13(
11407        &mut self,
11408        _: &ConvertToRot13,
11409        window: &mut Window,
11410        cx: &mut Context<Self>,
11411    ) {
11412        self.manipulate_text(window, cx, |text| {
11413            text.chars()
11414                .map(|c| match c {
11415                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11416                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11417                    _ => c,
11418                })
11419                .collect()
11420        })
11421    }
11422
11423    pub fn convert_to_rot47(
11424        &mut self,
11425        _: &ConvertToRot47,
11426        window: &mut Window,
11427        cx: &mut Context<Self>,
11428    ) {
11429        self.manipulate_text(window, cx, |text| {
11430            text.chars()
11431                .map(|c| {
11432                    let code_point = c as u32;
11433                    if code_point >= 33 && code_point <= 126 {
11434                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11435                    }
11436                    c
11437                })
11438                .collect()
11439        })
11440    }
11441
11442    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11443    where
11444        Fn: FnMut(&str) -> String,
11445    {
11446        let buffer = self.buffer.read(cx).snapshot(cx);
11447
11448        let mut new_selections = Vec::new();
11449        let mut edits = Vec::new();
11450        let mut selection_adjustment = 0i32;
11451
11452        for selection in self.selections.all_adjusted(cx) {
11453            let selection_is_empty = selection.is_empty();
11454
11455            let (start, end) = if selection_is_empty {
11456                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11457                (word_range.start, word_range.end)
11458            } else {
11459                (
11460                    buffer.point_to_offset(selection.start),
11461                    buffer.point_to_offset(selection.end),
11462                )
11463            };
11464
11465            let text = buffer.text_for_range(start..end).collect::<String>();
11466            let old_length = text.len() as i32;
11467            let text = callback(&text);
11468
11469            new_selections.push(Selection {
11470                start: (start as i32 - selection_adjustment) as usize,
11471                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11472                goal: SelectionGoal::None,
11473                id: selection.id,
11474                reversed: selection.reversed,
11475            });
11476
11477            selection_adjustment += old_length - text.len() as i32;
11478
11479            edits.push((start..end, text));
11480        }
11481
11482        self.transact(window, cx, |this, window, cx| {
11483            this.buffer.update(cx, |buffer, cx| {
11484                buffer.edit(edits, None, cx);
11485            });
11486
11487            this.change_selections(Default::default(), window, cx, |s| {
11488                s.select(new_selections);
11489            });
11490
11491            this.request_autoscroll(Autoscroll::fit(), cx);
11492        });
11493    }
11494
11495    pub fn move_selection_on_drop(
11496        &mut self,
11497        selection: &Selection<Anchor>,
11498        target: DisplayPoint,
11499        is_cut: bool,
11500        window: &mut Window,
11501        cx: &mut Context<Self>,
11502    ) {
11503        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11504        let buffer = &display_map.buffer_snapshot;
11505        let mut edits = Vec::new();
11506        let insert_point = display_map
11507            .clip_point(target, Bias::Left)
11508            .to_point(&display_map);
11509        let text = buffer
11510            .text_for_range(selection.start..selection.end)
11511            .collect::<String>();
11512        if is_cut {
11513            edits.push(((selection.start..selection.end), String::new()));
11514        }
11515        let insert_anchor = buffer.anchor_before(insert_point);
11516        edits.push(((insert_anchor..insert_anchor), text));
11517        let last_edit_start = insert_anchor.bias_left(buffer);
11518        let last_edit_end = insert_anchor.bias_right(buffer);
11519        self.transact(window, cx, |this, window, cx| {
11520            this.buffer.update(cx, |buffer, cx| {
11521                buffer.edit(edits, None, cx);
11522            });
11523            this.change_selections(Default::default(), window, cx, |s| {
11524                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11525            });
11526        });
11527    }
11528
11529    pub fn clear_selection_drag_state(&mut self) {
11530        self.selection_drag_state = SelectionDragState::None;
11531    }
11532
11533    pub fn duplicate(
11534        &mut self,
11535        upwards: bool,
11536        whole_lines: bool,
11537        window: &mut Window,
11538        cx: &mut Context<Self>,
11539    ) {
11540        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11541
11542        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11543        let buffer = &display_map.buffer_snapshot;
11544        let selections = self.selections.all::<Point>(cx);
11545
11546        let mut edits = Vec::new();
11547        let mut selections_iter = selections.iter().peekable();
11548        while let Some(selection) = selections_iter.next() {
11549            let mut rows = selection.spanned_rows(false, &display_map);
11550            // duplicate line-wise
11551            if whole_lines || selection.start == selection.end {
11552                // Avoid duplicating the same lines twice.
11553                while let Some(next_selection) = selections_iter.peek() {
11554                    let next_rows = next_selection.spanned_rows(false, &display_map);
11555                    if next_rows.start < rows.end {
11556                        rows.end = next_rows.end;
11557                        selections_iter.next().unwrap();
11558                    } else {
11559                        break;
11560                    }
11561                }
11562
11563                // Copy the text from the selected row region and splice it either at the start
11564                // or end of the region.
11565                let start = Point::new(rows.start.0, 0);
11566                let end = Point::new(
11567                    rows.end.previous_row().0,
11568                    buffer.line_len(rows.end.previous_row()),
11569                );
11570                let text = buffer
11571                    .text_for_range(start..end)
11572                    .chain(Some("\n"))
11573                    .collect::<String>();
11574                let insert_location = if upwards {
11575                    Point::new(rows.end.0, 0)
11576                } else {
11577                    start
11578                };
11579                edits.push((insert_location..insert_location, text));
11580            } else {
11581                // duplicate character-wise
11582                let start = selection.start;
11583                let end = selection.end;
11584                let text = buffer.text_for_range(start..end).collect::<String>();
11585                edits.push((selection.end..selection.end, text));
11586            }
11587        }
11588
11589        self.transact(window, cx, |this, _, cx| {
11590            this.buffer.update(cx, |buffer, cx| {
11591                buffer.edit(edits, None, cx);
11592            });
11593
11594            this.request_autoscroll(Autoscroll::fit(), cx);
11595        });
11596    }
11597
11598    pub fn duplicate_line_up(
11599        &mut self,
11600        _: &DuplicateLineUp,
11601        window: &mut Window,
11602        cx: &mut Context<Self>,
11603    ) {
11604        self.duplicate(true, true, window, cx);
11605    }
11606
11607    pub fn duplicate_line_down(
11608        &mut self,
11609        _: &DuplicateLineDown,
11610        window: &mut Window,
11611        cx: &mut Context<Self>,
11612    ) {
11613        self.duplicate(false, true, window, cx);
11614    }
11615
11616    pub fn duplicate_selection(
11617        &mut self,
11618        _: &DuplicateSelection,
11619        window: &mut Window,
11620        cx: &mut Context<Self>,
11621    ) {
11622        self.duplicate(false, false, window, cx);
11623    }
11624
11625    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11626        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11627        if self.mode.is_single_line() {
11628            cx.propagate();
11629            return;
11630        }
11631
11632        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11633        let buffer = self.buffer.read(cx).snapshot(cx);
11634
11635        let mut edits = Vec::new();
11636        let mut unfold_ranges = Vec::new();
11637        let mut refold_creases = Vec::new();
11638
11639        let selections = self.selections.all::<Point>(cx);
11640        let mut selections = selections.iter().peekable();
11641        let mut contiguous_row_selections = Vec::new();
11642        let mut new_selections = Vec::new();
11643
11644        while let Some(selection) = selections.next() {
11645            // Find all the selections that span a contiguous row range
11646            let (start_row, end_row) = consume_contiguous_rows(
11647                &mut contiguous_row_selections,
11648                selection,
11649                &display_map,
11650                &mut selections,
11651            );
11652
11653            // Move the text spanned by the row range to be before the line preceding the row range
11654            if start_row.0 > 0 {
11655                let range_to_move = Point::new(
11656                    start_row.previous_row().0,
11657                    buffer.line_len(start_row.previous_row()),
11658                )
11659                    ..Point::new(
11660                        end_row.previous_row().0,
11661                        buffer.line_len(end_row.previous_row()),
11662                    );
11663                let insertion_point = display_map
11664                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11665                    .0;
11666
11667                // Don't move lines across excerpts
11668                if buffer
11669                    .excerpt_containing(insertion_point..range_to_move.end)
11670                    .is_some()
11671                {
11672                    let text = buffer
11673                        .text_for_range(range_to_move.clone())
11674                        .flat_map(|s| s.chars())
11675                        .skip(1)
11676                        .chain(['\n'])
11677                        .collect::<String>();
11678
11679                    edits.push((
11680                        buffer.anchor_after(range_to_move.start)
11681                            ..buffer.anchor_before(range_to_move.end),
11682                        String::new(),
11683                    ));
11684                    let insertion_anchor = buffer.anchor_after(insertion_point);
11685                    edits.push((insertion_anchor..insertion_anchor, text));
11686
11687                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11688
11689                    // Move selections up
11690                    new_selections.extend(contiguous_row_selections.drain(..).map(
11691                        |mut selection| {
11692                            selection.start.row -= row_delta;
11693                            selection.end.row -= row_delta;
11694                            selection
11695                        },
11696                    ));
11697
11698                    // Move folds up
11699                    unfold_ranges.push(range_to_move.clone());
11700                    for fold in display_map.folds_in_range(
11701                        buffer.anchor_before(range_to_move.start)
11702                            ..buffer.anchor_after(range_to_move.end),
11703                    ) {
11704                        let mut start = fold.range.start.to_point(&buffer);
11705                        let mut end = fold.range.end.to_point(&buffer);
11706                        start.row -= row_delta;
11707                        end.row -= row_delta;
11708                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11709                    }
11710                }
11711            }
11712
11713            // If we didn't move line(s), preserve the existing selections
11714            new_selections.append(&mut contiguous_row_selections);
11715        }
11716
11717        self.transact(window, cx, |this, window, cx| {
11718            this.unfold_ranges(&unfold_ranges, true, true, cx);
11719            this.buffer.update(cx, |buffer, cx| {
11720                for (range, text) in edits {
11721                    buffer.edit([(range, text)], None, cx);
11722                }
11723            });
11724            this.fold_creases(refold_creases, true, window, cx);
11725            this.change_selections(Default::default(), window, cx, |s| {
11726                s.select(new_selections);
11727            })
11728        });
11729    }
11730
11731    pub fn move_line_down(
11732        &mut self,
11733        _: &MoveLineDown,
11734        window: &mut Window,
11735        cx: &mut Context<Self>,
11736    ) {
11737        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11738        if self.mode.is_single_line() {
11739            cx.propagate();
11740            return;
11741        }
11742
11743        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11744        let buffer = self.buffer.read(cx).snapshot(cx);
11745
11746        let mut edits = Vec::new();
11747        let mut unfold_ranges = Vec::new();
11748        let mut refold_creases = Vec::new();
11749
11750        let selections = self.selections.all::<Point>(cx);
11751        let mut selections = selections.iter().peekable();
11752        let mut contiguous_row_selections = Vec::new();
11753        let mut new_selections = Vec::new();
11754
11755        while let Some(selection) = selections.next() {
11756            // Find all the selections that span a contiguous row range
11757            let (start_row, end_row) = consume_contiguous_rows(
11758                &mut contiguous_row_selections,
11759                selection,
11760                &display_map,
11761                &mut selections,
11762            );
11763
11764            // Move the text spanned by the row range to be after the last line of the row range
11765            if end_row.0 <= buffer.max_point().row {
11766                let range_to_move =
11767                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11768                let insertion_point = display_map
11769                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11770                    .0;
11771
11772                // Don't move lines across excerpt boundaries
11773                if buffer
11774                    .excerpt_containing(range_to_move.start..insertion_point)
11775                    .is_some()
11776                {
11777                    let mut text = String::from("\n");
11778                    text.extend(buffer.text_for_range(range_to_move.clone()));
11779                    text.pop(); // Drop trailing newline
11780                    edits.push((
11781                        buffer.anchor_after(range_to_move.start)
11782                            ..buffer.anchor_before(range_to_move.end),
11783                        String::new(),
11784                    ));
11785                    let insertion_anchor = buffer.anchor_after(insertion_point);
11786                    edits.push((insertion_anchor..insertion_anchor, text));
11787
11788                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11789
11790                    // Move selections down
11791                    new_selections.extend(contiguous_row_selections.drain(..).map(
11792                        |mut selection| {
11793                            selection.start.row += row_delta;
11794                            selection.end.row += row_delta;
11795                            selection
11796                        },
11797                    ));
11798
11799                    // Move folds down
11800                    unfold_ranges.push(range_to_move.clone());
11801                    for fold in display_map.folds_in_range(
11802                        buffer.anchor_before(range_to_move.start)
11803                            ..buffer.anchor_after(range_to_move.end),
11804                    ) {
11805                        let mut start = fold.range.start.to_point(&buffer);
11806                        let mut end = fold.range.end.to_point(&buffer);
11807                        start.row += row_delta;
11808                        end.row += row_delta;
11809                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11810                    }
11811                }
11812            }
11813
11814            // If we didn't move line(s), preserve the existing selections
11815            new_selections.append(&mut contiguous_row_selections);
11816        }
11817
11818        self.transact(window, cx, |this, window, cx| {
11819            this.unfold_ranges(&unfold_ranges, true, true, cx);
11820            this.buffer.update(cx, |buffer, cx| {
11821                for (range, text) in edits {
11822                    buffer.edit([(range, text)], None, cx);
11823                }
11824            });
11825            this.fold_creases(refold_creases, true, window, cx);
11826            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11827        });
11828    }
11829
11830    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11831        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11832        let text_layout_details = &self.text_layout_details(window);
11833        self.transact(window, cx, |this, window, cx| {
11834            let edits = this.change_selections(Default::default(), window, cx, |s| {
11835                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11836                s.move_with(|display_map, selection| {
11837                    if !selection.is_empty() {
11838                        return;
11839                    }
11840
11841                    let mut head = selection.head();
11842                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11843                    if head.column() == display_map.line_len(head.row()) {
11844                        transpose_offset = display_map
11845                            .buffer_snapshot
11846                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11847                    }
11848
11849                    if transpose_offset == 0 {
11850                        return;
11851                    }
11852
11853                    *head.column_mut() += 1;
11854                    head = display_map.clip_point(head, Bias::Right);
11855                    let goal = SelectionGoal::HorizontalPosition(
11856                        display_map
11857                            .x_for_display_point(head, text_layout_details)
11858                            .into(),
11859                    );
11860                    selection.collapse_to(head, goal);
11861
11862                    let transpose_start = display_map
11863                        .buffer_snapshot
11864                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11865                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11866                        let transpose_end = display_map
11867                            .buffer_snapshot
11868                            .clip_offset(transpose_offset + 1, Bias::Right);
11869                        if let Some(ch) =
11870                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11871                        {
11872                            edits.push((transpose_start..transpose_offset, String::new()));
11873                            edits.push((transpose_end..transpose_end, ch.to_string()));
11874                        }
11875                    }
11876                });
11877                edits
11878            });
11879            this.buffer
11880                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11881            let selections = this.selections.all::<usize>(cx);
11882            this.change_selections(Default::default(), window, cx, |s| {
11883                s.select(selections);
11884            });
11885        });
11886    }
11887
11888    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11889        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11890        if self.mode.is_single_line() {
11891            cx.propagate();
11892            return;
11893        }
11894
11895        self.rewrap_impl(RewrapOptions::default(), cx)
11896    }
11897
11898    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11899        let buffer = self.buffer.read(cx).snapshot(cx);
11900        let selections = self.selections.all::<Point>(cx);
11901
11902        #[derive(Clone, Debug, PartialEq)]
11903        enum CommentFormat {
11904            /// single line comment, with prefix for line
11905            Line(String),
11906            /// single line within a block comment, with prefix for line
11907            BlockLine(String),
11908            /// a single line of a block comment that includes the initial delimiter
11909            BlockCommentWithStart(BlockCommentConfig),
11910            /// a single line of a block comment that includes the ending delimiter
11911            BlockCommentWithEnd(BlockCommentConfig),
11912        }
11913
11914        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11915        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11916            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11917                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11918                .peekable();
11919
11920            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11921                row
11922            } else {
11923                return Vec::new();
11924            };
11925
11926            let language_settings = buffer.language_settings_at(selection.head(), cx);
11927            let language_scope = buffer.language_scope_at(selection.head());
11928
11929            let indent_and_prefix_for_row =
11930                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11931                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11932                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11933                        &language_scope
11934                    {
11935                        let indent_end = Point::new(row, indent.len);
11936                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11937                        let line_text_after_indent = buffer
11938                            .text_for_range(indent_end..line_end)
11939                            .collect::<String>();
11940
11941                        let is_within_comment_override = buffer
11942                            .language_scope_at(indent_end)
11943                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11944                        let comment_delimiters = if is_within_comment_override {
11945                            // we are within a comment syntax node, but we don't
11946                            // yet know what kind of comment: block, doc or line
11947                            match (
11948                                language_scope.documentation_comment(),
11949                                language_scope.block_comment(),
11950                            ) {
11951                                (Some(config), _) | (_, Some(config))
11952                                    if buffer.contains_str_at(indent_end, &config.start) =>
11953                                {
11954                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11955                                }
11956                                (Some(config), _) | (_, Some(config))
11957                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11958                                {
11959                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11960                                }
11961                                (Some(config), _) | (_, Some(config))
11962                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11963                                {
11964                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11965                                }
11966                                (_, _) => language_scope
11967                                    .line_comment_prefixes()
11968                                    .iter()
11969                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11970                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11971                            }
11972                        } else {
11973                            // we not in an overridden comment node, but we may
11974                            // be within a non-overridden line comment node
11975                            language_scope
11976                                .line_comment_prefixes()
11977                                .iter()
11978                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11979                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11980                        };
11981
11982                        let rewrap_prefix = language_scope
11983                            .rewrap_prefixes()
11984                            .iter()
11985                            .find_map(|prefix_regex| {
11986                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11987                                    if mat.start() == 0 {
11988                                        Some(mat.as_str().to_string())
11989                                    } else {
11990                                        None
11991                                    }
11992                                })
11993                            })
11994                            .flatten();
11995                        (comment_delimiters, rewrap_prefix)
11996                    } else {
11997                        (None, None)
11998                    };
11999                    (indent, comment_prefix, rewrap_prefix)
12000                };
12001
12002            let mut ranges = Vec::new();
12003            let from_empty_selection = selection.is_empty();
12004
12005            let mut current_range_start = first_row;
12006            let mut prev_row = first_row;
12007            let (
12008                mut current_range_indent,
12009                mut current_range_comment_delimiters,
12010                mut current_range_rewrap_prefix,
12011            ) = indent_and_prefix_for_row(first_row);
12012
12013            for row in non_blank_rows_iter.skip(1) {
12014                let has_paragraph_break = row > prev_row + 1;
12015
12016                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12017                    indent_and_prefix_for_row(row);
12018
12019                let has_indent_change = row_indent != current_range_indent;
12020                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12021
12022                let has_boundary_change = has_comment_change
12023                    || row_rewrap_prefix.is_some()
12024                    || (has_indent_change && current_range_comment_delimiters.is_some());
12025
12026                if has_paragraph_break || has_boundary_change {
12027                    ranges.push((
12028                        language_settings.clone(),
12029                        Point::new(current_range_start, 0)
12030                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12031                        current_range_indent,
12032                        current_range_comment_delimiters.clone(),
12033                        current_range_rewrap_prefix.clone(),
12034                        from_empty_selection,
12035                    ));
12036                    current_range_start = row;
12037                    current_range_indent = row_indent;
12038                    current_range_comment_delimiters = row_comment_delimiters;
12039                    current_range_rewrap_prefix = row_rewrap_prefix;
12040                }
12041                prev_row = row;
12042            }
12043
12044            ranges.push((
12045                language_settings.clone(),
12046                Point::new(current_range_start, 0)
12047                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12048                current_range_indent,
12049                current_range_comment_delimiters,
12050                current_range_rewrap_prefix,
12051                from_empty_selection,
12052            ));
12053
12054            ranges
12055        });
12056
12057        let mut edits = Vec::new();
12058        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12059
12060        for (
12061            language_settings,
12062            wrap_range,
12063            mut indent_size,
12064            comment_prefix,
12065            rewrap_prefix,
12066            from_empty_selection,
12067        ) in wrap_ranges
12068        {
12069            let mut start_row = wrap_range.start.row;
12070            let mut end_row = wrap_range.end.row;
12071
12072            // Skip selections that overlap with a range that has already been rewrapped.
12073            let selection_range = start_row..end_row;
12074            if rewrapped_row_ranges
12075                .iter()
12076                .any(|range| range.overlaps(&selection_range))
12077            {
12078                continue;
12079            }
12080
12081            let tab_size = language_settings.tab_size;
12082
12083            let (line_prefix, inside_comment) = match &comment_prefix {
12084                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12085                    (Some(prefix.as_str()), true)
12086                }
12087                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12088                    (Some(prefix.as_ref()), true)
12089                }
12090                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12091                    start: _,
12092                    end: _,
12093                    prefix,
12094                    tab_size,
12095                })) => {
12096                    indent_size.len += tab_size;
12097                    (Some(prefix.as_ref()), true)
12098                }
12099                None => (None, false),
12100            };
12101            let indent_prefix = indent_size.chars().collect::<String>();
12102            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12103
12104            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12105                RewrapBehavior::InComments => inside_comment,
12106                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12107                RewrapBehavior::Anywhere => true,
12108            };
12109
12110            let should_rewrap = options.override_language_settings
12111                || allow_rewrap_based_on_language
12112                || self.hard_wrap.is_some();
12113            if !should_rewrap {
12114                continue;
12115            }
12116
12117            if from_empty_selection {
12118                'expand_upwards: while start_row > 0 {
12119                    let prev_row = start_row - 1;
12120                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12121                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12122                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12123                    {
12124                        start_row = prev_row;
12125                    } else {
12126                        break 'expand_upwards;
12127                    }
12128                }
12129
12130                'expand_downwards: while end_row < buffer.max_point().row {
12131                    let next_row = end_row + 1;
12132                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12133                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12134                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12135                    {
12136                        end_row = next_row;
12137                    } else {
12138                        break 'expand_downwards;
12139                    }
12140                }
12141            }
12142
12143            let start = Point::new(start_row, 0);
12144            let start_offset = start.to_offset(&buffer);
12145            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12146            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12147            let mut first_line_delimiter = None;
12148            let mut last_line_delimiter = None;
12149            let Some(lines_without_prefixes) = selection_text
12150                .lines()
12151                .enumerate()
12152                .map(|(ix, line)| {
12153                    let line_trimmed = line.trim_start();
12154                    if rewrap_prefix.is_some() && ix > 0 {
12155                        Ok(line_trimmed)
12156                    } else if let Some(
12157                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12158                            start,
12159                            prefix,
12160                            end,
12161                            tab_size,
12162                        })
12163                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12164                            start,
12165                            prefix,
12166                            end,
12167                            tab_size,
12168                        }),
12169                    ) = &comment_prefix
12170                    {
12171                        let line_trimmed = line_trimmed
12172                            .strip_prefix(start.as_ref())
12173                            .map(|s| {
12174                                let mut indent_size = indent_size;
12175                                indent_size.len -= tab_size;
12176                                let indent_prefix: String = indent_size.chars().collect();
12177                                first_line_delimiter = Some((indent_prefix, start));
12178                                s.trim_start()
12179                            })
12180                            .unwrap_or(line_trimmed);
12181                        let line_trimmed = line_trimmed
12182                            .strip_suffix(end.as_ref())
12183                            .map(|s| {
12184                                last_line_delimiter = Some(end);
12185                                s.trim_end()
12186                            })
12187                            .unwrap_or(line_trimmed);
12188                        let line_trimmed = line_trimmed
12189                            .strip_prefix(prefix.as_ref())
12190                            .unwrap_or(line_trimmed);
12191                        Ok(line_trimmed)
12192                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12193                        line_trimmed.strip_prefix(prefix).with_context(|| {
12194                            format!("line did not start with prefix {prefix:?}: {line:?}")
12195                        })
12196                    } else {
12197                        line_trimmed
12198                            .strip_prefix(&line_prefix.trim_start())
12199                            .with_context(|| {
12200                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12201                            })
12202                    }
12203                })
12204                .collect::<Result<Vec<_>, _>>()
12205                .log_err()
12206            else {
12207                continue;
12208            };
12209
12210            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12211                buffer
12212                    .language_settings_at(Point::new(start_row, 0), cx)
12213                    .preferred_line_length as usize
12214            });
12215
12216            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12217                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12218            } else {
12219                line_prefix.clone()
12220            };
12221
12222            let wrapped_text = {
12223                let mut wrapped_text = wrap_with_prefix(
12224                    line_prefix,
12225                    subsequent_lines_prefix,
12226                    lines_without_prefixes.join("\n"),
12227                    wrap_column,
12228                    tab_size,
12229                    options.preserve_existing_whitespace,
12230                );
12231
12232                if let Some((indent, delimiter)) = first_line_delimiter {
12233                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12234                }
12235                if let Some(last_line) = last_line_delimiter {
12236                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12237                }
12238
12239                wrapped_text
12240            };
12241
12242            // TODO: should always use char-based diff while still supporting cursor behavior that
12243            // matches vim.
12244            let mut diff_options = DiffOptions::default();
12245            if options.override_language_settings {
12246                diff_options.max_word_diff_len = 0;
12247                diff_options.max_word_diff_line_count = 0;
12248            } else {
12249                diff_options.max_word_diff_len = usize::MAX;
12250                diff_options.max_word_diff_line_count = usize::MAX;
12251            }
12252
12253            for (old_range, new_text) in
12254                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12255            {
12256                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12257                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12258                edits.push((edit_start..edit_end, new_text));
12259            }
12260
12261            rewrapped_row_ranges.push(start_row..=end_row);
12262        }
12263
12264        self.buffer
12265            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12266    }
12267
12268    pub fn cut_common(
12269        &mut self,
12270        cut_no_selection_line: bool,
12271        window: &mut Window,
12272        cx: &mut Context<Self>,
12273    ) -> ClipboardItem {
12274        let mut text = String::new();
12275        let buffer = self.buffer.read(cx).snapshot(cx);
12276        let mut selections = self.selections.all::<Point>(cx);
12277        let mut clipboard_selections = Vec::with_capacity(selections.len());
12278        {
12279            let max_point = buffer.max_point();
12280            let mut is_first = true;
12281            for selection in &mut selections {
12282                let is_entire_line =
12283                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12284                if is_entire_line {
12285                    selection.start = Point::new(selection.start.row, 0);
12286                    if !selection.is_empty() && selection.end.column == 0 {
12287                        selection.end = cmp::min(max_point, selection.end);
12288                    } else {
12289                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12290                    }
12291                    selection.goal = SelectionGoal::None;
12292                }
12293                if is_first {
12294                    is_first = false;
12295                } else {
12296                    text += "\n";
12297                }
12298                let mut len = 0;
12299                for chunk in buffer.text_for_range(selection.start..selection.end) {
12300                    text.push_str(chunk);
12301                    len += chunk.len();
12302                }
12303                clipboard_selections.push(ClipboardSelection {
12304                    len,
12305                    is_entire_line,
12306                    first_line_indent: buffer
12307                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12308                        .len,
12309                });
12310            }
12311        }
12312
12313        self.transact(window, cx, |this, window, cx| {
12314            this.change_selections(Default::default(), window, cx, |s| {
12315                s.select(selections);
12316            });
12317            this.insert("", window, cx);
12318        });
12319        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12320    }
12321
12322    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12323        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12324        let item = self.cut_common(true, window, cx);
12325        cx.write_to_clipboard(item);
12326    }
12327
12328    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12329        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12330        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12331            s.move_with(|snapshot, sel| {
12332                if sel.is_empty() {
12333                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12334                }
12335                if sel.is_empty() {
12336                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12337                }
12338            });
12339        });
12340        let item = self.cut_common(true, window, cx);
12341        cx.set_global(KillRing(item))
12342    }
12343
12344    pub fn kill_ring_yank(
12345        &mut self,
12346        _: &KillRingYank,
12347        window: &mut Window,
12348        cx: &mut Context<Self>,
12349    ) {
12350        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12351        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12352            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12353                (kill_ring.text().to_string(), kill_ring.metadata_json())
12354            } else {
12355                return;
12356            }
12357        } else {
12358            return;
12359        };
12360        self.do_paste(&text, metadata, false, window, cx);
12361    }
12362
12363    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12364        self.do_copy(true, cx);
12365    }
12366
12367    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12368        self.do_copy(false, cx);
12369    }
12370
12371    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12372        let selections = self.selections.all::<Point>(cx);
12373        let buffer = self.buffer.read(cx).read(cx);
12374        let mut text = String::new();
12375
12376        let mut clipboard_selections = Vec::with_capacity(selections.len());
12377        {
12378            let max_point = buffer.max_point();
12379            let mut is_first = true;
12380            for selection in &selections {
12381                let mut start = selection.start;
12382                let mut end = selection.end;
12383                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12384                if is_entire_line {
12385                    start = Point::new(start.row, 0);
12386                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12387                }
12388
12389                let mut trimmed_selections = Vec::new();
12390                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12391                    let row = MultiBufferRow(start.row);
12392                    let first_indent = buffer.indent_size_for_line(row);
12393                    if first_indent.len == 0 || start.column > first_indent.len {
12394                        trimmed_selections.push(start..end);
12395                    } else {
12396                        trimmed_selections.push(
12397                            Point::new(row.0, first_indent.len)
12398                                ..Point::new(row.0, buffer.line_len(row)),
12399                        );
12400                        for row in start.row + 1..=end.row {
12401                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12402                            if row == end.row {
12403                                line_len = end.column;
12404                            }
12405                            if line_len == 0 {
12406                                trimmed_selections
12407                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12408                                continue;
12409                            }
12410                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12411                            if row_indent_size.len >= first_indent.len {
12412                                trimmed_selections.push(
12413                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12414                                );
12415                            } else {
12416                                trimmed_selections.clear();
12417                                trimmed_selections.push(start..end);
12418                                break;
12419                            }
12420                        }
12421                    }
12422                } else {
12423                    trimmed_selections.push(start..end);
12424                }
12425
12426                for trimmed_range in trimmed_selections {
12427                    if is_first {
12428                        is_first = false;
12429                    } else {
12430                        text += "\n";
12431                    }
12432                    let mut len = 0;
12433                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12434                        text.push_str(chunk);
12435                        len += chunk.len();
12436                    }
12437                    clipboard_selections.push(ClipboardSelection {
12438                        len,
12439                        is_entire_line,
12440                        first_line_indent: buffer
12441                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12442                            .len,
12443                    });
12444                }
12445            }
12446        }
12447
12448        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12449            text,
12450            clipboard_selections,
12451        ));
12452    }
12453
12454    pub fn do_paste(
12455        &mut self,
12456        text: &String,
12457        clipboard_selections: Option<Vec<ClipboardSelection>>,
12458        handle_entire_lines: bool,
12459        window: &mut Window,
12460        cx: &mut Context<Self>,
12461    ) {
12462        if self.read_only(cx) {
12463            return;
12464        }
12465
12466        let clipboard_text = Cow::Borrowed(text.as_str());
12467
12468        self.transact(window, cx, |this, window, cx| {
12469            let had_active_edit_prediction = this.has_active_edit_prediction();
12470            let old_selections = this.selections.all::<usize>(cx);
12471            let cursor_offset = this.selections.last::<usize>(cx).head();
12472
12473            if let Some(mut clipboard_selections) = clipboard_selections {
12474                let all_selections_were_entire_line =
12475                    clipboard_selections.iter().all(|s| s.is_entire_line);
12476                let first_selection_indent_column =
12477                    clipboard_selections.first().map(|s| s.first_line_indent);
12478                if clipboard_selections.len() != old_selections.len() {
12479                    clipboard_selections.drain(..);
12480                }
12481                let mut auto_indent_on_paste = true;
12482
12483                this.buffer.update(cx, |buffer, cx| {
12484                    let snapshot = buffer.read(cx);
12485                    auto_indent_on_paste = snapshot
12486                        .language_settings_at(cursor_offset, cx)
12487                        .auto_indent_on_paste;
12488
12489                    let mut start_offset = 0;
12490                    let mut edits = Vec::new();
12491                    let mut original_indent_columns = Vec::new();
12492                    for (ix, selection) in old_selections.iter().enumerate() {
12493                        let to_insert;
12494                        let entire_line;
12495                        let original_indent_column;
12496                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12497                            let end_offset = start_offset + clipboard_selection.len;
12498                            to_insert = &clipboard_text[start_offset..end_offset];
12499                            entire_line = clipboard_selection.is_entire_line;
12500                            start_offset = end_offset + 1;
12501                            original_indent_column = Some(clipboard_selection.first_line_indent);
12502                        } else {
12503                            to_insert = &*clipboard_text;
12504                            entire_line = all_selections_were_entire_line;
12505                            original_indent_column = first_selection_indent_column
12506                        }
12507
12508                        let (range, to_insert) =
12509                            if selection.is_empty() && handle_entire_lines && entire_line {
12510                                // If the corresponding selection was empty when this slice of the
12511                                // clipboard text was written, then the entire line containing the
12512                                // selection was copied. If this selection is also currently empty,
12513                                // then paste the line before the current line of the buffer.
12514                                let column = selection.start.to_point(&snapshot).column as usize;
12515                                let line_start = selection.start - column;
12516                                (line_start..line_start, Cow::Borrowed(to_insert))
12517                            } else {
12518                                let language = snapshot.language_at(selection.head());
12519                                let range = selection.range();
12520                                if let Some(language) = language
12521                                    && language.name() == "Markdown".into()
12522                                {
12523                                    edit_for_markdown_paste(
12524                                        &snapshot,
12525                                        range,
12526                                        to_insert,
12527                                        url::Url::parse(to_insert).ok(),
12528                                    )
12529                                } else {
12530                                    (range, Cow::Borrowed(to_insert))
12531                                }
12532                            };
12533
12534                        edits.push((range, to_insert));
12535                        original_indent_columns.push(original_indent_column);
12536                    }
12537                    drop(snapshot);
12538
12539                    buffer.edit(
12540                        edits,
12541                        if auto_indent_on_paste {
12542                            Some(AutoindentMode::Block {
12543                                original_indent_columns,
12544                            })
12545                        } else {
12546                            None
12547                        },
12548                        cx,
12549                    );
12550                });
12551
12552                let selections = this.selections.all::<usize>(cx);
12553                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12554            } else {
12555                let url = url::Url::parse(&clipboard_text).ok();
12556
12557                let auto_indent_mode = if !clipboard_text.is_empty() {
12558                    Some(AutoindentMode::Block {
12559                        original_indent_columns: Vec::new(),
12560                    })
12561                } else {
12562                    None
12563                };
12564
12565                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12566                    let snapshot = buffer.snapshot(cx);
12567
12568                    let anchors = old_selections
12569                        .iter()
12570                        .map(|s| {
12571                            let anchor = snapshot.anchor_after(s.head());
12572                            s.map(|_| anchor)
12573                        })
12574                        .collect::<Vec<_>>();
12575
12576                    let mut edits = Vec::new();
12577
12578                    for selection in old_selections.iter() {
12579                        let language = snapshot.language_at(selection.head());
12580                        let range = selection.range();
12581
12582                        let (edit_range, edit_text) = if let Some(language) = language
12583                            && language.name() == "Markdown".into()
12584                        {
12585                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12586                        } else {
12587                            (range, clipboard_text.clone())
12588                        };
12589
12590                        edits.push((edit_range, edit_text));
12591                    }
12592
12593                    drop(snapshot);
12594                    buffer.edit(edits, auto_indent_mode, cx);
12595
12596                    anchors
12597                });
12598
12599                this.change_selections(Default::default(), window, cx, |s| {
12600                    s.select_anchors(selection_anchors);
12601                });
12602            }
12603
12604            let trigger_in_words =
12605                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12606
12607            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12608        });
12609    }
12610
12611    pub fn diff_clipboard_with_selection(
12612        &mut self,
12613        _: &DiffClipboardWithSelection,
12614        window: &mut Window,
12615        cx: &mut Context<Self>,
12616    ) {
12617        let selections = self.selections.all::<usize>(cx);
12618
12619        if selections.is_empty() {
12620            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12621            return;
12622        };
12623
12624        let clipboard_text = match cx.read_from_clipboard() {
12625            Some(item) => match item.entries().first() {
12626                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12627                _ => None,
12628            },
12629            None => None,
12630        };
12631
12632        let Some(clipboard_text) = clipboard_text else {
12633            log::warn!("Clipboard doesn't contain text.");
12634            return;
12635        };
12636
12637        window.dispatch_action(
12638            Box::new(DiffClipboardWithSelectionData {
12639                clipboard_text,
12640                editor: cx.entity(),
12641            }),
12642            cx,
12643        );
12644    }
12645
12646    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12647        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12648        if let Some(item) = cx.read_from_clipboard() {
12649            let entries = item.entries();
12650
12651            match entries.first() {
12652                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12653                // of all the pasted entries.
12654                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12655                    .do_paste(
12656                        clipboard_string.text(),
12657                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12658                        true,
12659                        window,
12660                        cx,
12661                    ),
12662                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12663            }
12664        }
12665    }
12666
12667    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12668        if self.read_only(cx) {
12669            return;
12670        }
12671
12672        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12673
12674        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12675            if let Some((selections, _)) =
12676                self.selection_history.transaction(transaction_id).cloned()
12677            {
12678                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12679                    s.select_anchors(selections.to_vec());
12680                });
12681            } else {
12682                log::error!(
12683                    "No entry in selection_history found for undo. \
12684                     This may correspond to a bug where undo does not update the selection. \
12685                     If this is occurring, please add details to \
12686                     https://github.com/zed-industries/zed/issues/22692"
12687                );
12688            }
12689            self.request_autoscroll(Autoscroll::fit(), cx);
12690            self.unmark_text(window, cx);
12691            self.refresh_edit_prediction(true, false, window, cx);
12692            cx.emit(EditorEvent::Edited { transaction_id });
12693            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12694        }
12695    }
12696
12697    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12698        if self.read_only(cx) {
12699            return;
12700        }
12701
12702        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12703
12704        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12705            if let Some((_, Some(selections))) =
12706                self.selection_history.transaction(transaction_id).cloned()
12707            {
12708                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12709                    s.select_anchors(selections.to_vec());
12710                });
12711            } else {
12712                log::error!(
12713                    "No entry in selection_history found for redo. \
12714                     This may correspond to a bug where undo does not update the selection. \
12715                     If this is occurring, please add details to \
12716                     https://github.com/zed-industries/zed/issues/22692"
12717                );
12718            }
12719            self.request_autoscroll(Autoscroll::fit(), cx);
12720            self.unmark_text(window, cx);
12721            self.refresh_edit_prediction(true, false, window, cx);
12722            cx.emit(EditorEvent::Edited { transaction_id });
12723        }
12724    }
12725
12726    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12727        self.buffer
12728            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12729    }
12730
12731    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12732        self.buffer
12733            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12734    }
12735
12736    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12737        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12738        self.change_selections(Default::default(), window, cx, |s| {
12739            s.move_with(|map, selection| {
12740                let cursor = if selection.is_empty() {
12741                    movement::left(map, selection.start)
12742                } else {
12743                    selection.start
12744                };
12745                selection.collapse_to(cursor, SelectionGoal::None);
12746            });
12747        })
12748    }
12749
12750    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12751        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12752        self.change_selections(Default::default(), window, cx, |s| {
12753            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12754        })
12755    }
12756
12757    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12758        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12759        self.change_selections(Default::default(), window, cx, |s| {
12760            s.move_with(|map, selection| {
12761                let cursor = if selection.is_empty() {
12762                    movement::right(map, selection.end)
12763                } else {
12764                    selection.end
12765                };
12766                selection.collapse_to(cursor, SelectionGoal::None)
12767            });
12768        })
12769    }
12770
12771    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12772        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12773        self.change_selections(Default::default(), window, cx, |s| {
12774            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12775        })
12776    }
12777
12778    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12779        if self.take_rename(true, window, cx).is_some() {
12780            return;
12781        }
12782
12783        if self.mode.is_single_line() {
12784            cx.propagate();
12785            return;
12786        }
12787
12788        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12789
12790        let text_layout_details = &self.text_layout_details(window);
12791        let selection_count = self.selections.count();
12792        let first_selection = self.selections.first_anchor();
12793
12794        self.change_selections(Default::default(), window, cx, |s| {
12795            s.move_with(|map, selection| {
12796                if !selection.is_empty() {
12797                    selection.goal = SelectionGoal::None;
12798                }
12799                let (cursor, goal) = movement::up(
12800                    map,
12801                    selection.start,
12802                    selection.goal,
12803                    false,
12804                    text_layout_details,
12805                );
12806                selection.collapse_to(cursor, goal);
12807            });
12808        });
12809
12810        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12811        {
12812            cx.propagate();
12813        }
12814    }
12815
12816    pub fn move_up_by_lines(
12817        &mut self,
12818        action: &MoveUpByLines,
12819        window: &mut Window,
12820        cx: &mut Context<Self>,
12821    ) {
12822        if self.take_rename(true, window, cx).is_some() {
12823            return;
12824        }
12825
12826        if self.mode.is_single_line() {
12827            cx.propagate();
12828            return;
12829        }
12830
12831        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12832
12833        let text_layout_details = &self.text_layout_details(window);
12834
12835        self.change_selections(Default::default(), window, cx, |s| {
12836            s.move_with(|map, selection| {
12837                if !selection.is_empty() {
12838                    selection.goal = SelectionGoal::None;
12839                }
12840                let (cursor, goal) = movement::up_by_rows(
12841                    map,
12842                    selection.start,
12843                    action.lines,
12844                    selection.goal,
12845                    false,
12846                    text_layout_details,
12847                );
12848                selection.collapse_to(cursor, goal);
12849            });
12850        })
12851    }
12852
12853    pub fn move_down_by_lines(
12854        &mut self,
12855        action: &MoveDownByLines,
12856        window: &mut Window,
12857        cx: &mut Context<Self>,
12858    ) {
12859        if self.take_rename(true, window, cx).is_some() {
12860            return;
12861        }
12862
12863        if self.mode.is_single_line() {
12864            cx.propagate();
12865            return;
12866        }
12867
12868        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12869
12870        let text_layout_details = &self.text_layout_details(window);
12871
12872        self.change_selections(Default::default(), window, cx, |s| {
12873            s.move_with(|map, selection| {
12874                if !selection.is_empty() {
12875                    selection.goal = SelectionGoal::None;
12876                }
12877                let (cursor, goal) = movement::down_by_rows(
12878                    map,
12879                    selection.start,
12880                    action.lines,
12881                    selection.goal,
12882                    false,
12883                    text_layout_details,
12884                );
12885                selection.collapse_to(cursor, goal);
12886            });
12887        })
12888    }
12889
12890    pub fn select_down_by_lines(
12891        &mut self,
12892        action: &SelectDownByLines,
12893        window: &mut Window,
12894        cx: &mut Context<Self>,
12895    ) {
12896        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12897        let text_layout_details = &self.text_layout_details(window);
12898        self.change_selections(Default::default(), window, cx, |s| {
12899            s.move_heads_with(|map, head, goal| {
12900                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12901            })
12902        })
12903    }
12904
12905    pub fn select_up_by_lines(
12906        &mut self,
12907        action: &SelectUpByLines,
12908        window: &mut Window,
12909        cx: &mut Context<Self>,
12910    ) {
12911        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12912        let text_layout_details = &self.text_layout_details(window);
12913        self.change_selections(Default::default(), window, cx, |s| {
12914            s.move_heads_with(|map, head, goal| {
12915                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12916            })
12917        })
12918    }
12919
12920    pub fn select_page_up(
12921        &mut self,
12922        _: &SelectPageUp,
12923        window: &mut Window,
12924        cx: &mut Context<Self>,
12925    ) {
12926        let Some(row_count) = self.visible_row_count() else {
12927            return;
12928        };
12929
12930        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12931
12932        let text_layout_details = &self.text_layout_details(window);
12933
12934        self.change_selections(Default::default(), window, cx, |s| {
12935            s.move_heads_with(|map, head, goal| {
12936                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12937            })
12938        })
12939    }
12940
12941    pub fn move_page_up(
12942        &mut self,
12943        action: &MovePageUp,
12944        window: &mut Window,
12945        cx: &mut Context<Self>,
12946    ) {
12947        if self.take_rename(true, window, cx).is_some() {
12948            return;
12949        }
12950
12951        if self
12952            .context_menu
12953            .borrow_mut()
12954            .as_mut()
12955            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12956            .unwrap_or(false)
12957        {
12958            return;
12959        }
12960
12961        if matches!(self.mode, EditorMode::SingleLine) {
12962            cx.propagate();
12963            return;
12964        }
12965
12966        let Some(row_count) = self.visible_row_count() else {
12967            return;
12968        };
12969
12970        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12971
12972        let effects = if action.center_cursor {
12973            SelectionEffects::scroll(Autoscroll::center())
12974        } else {
12975            SelectionEffects::default()
12976        };
12977
12978        let text_layout_details = &self.text_layout_details(window);
12979
12980        self.change_selections(effects, window, cx, |s| {
12981            s.move_with(|map, selection| {
12982                if !selection.is_empty() {
12983                    selection.goal = SelectionGoal::None;
12984                }
12985                let (cursor, goal) = movement::up_by_rows(
12986                    map,
12987                    selection.end,
12988                    row_count,
12989                    selection.goal,
12990                    false,
12991                    text_layout_details,
12992                );
12993                selection.collapse_to(cursor, goal);
12994            });
12995        });
12996    }
12997
12998    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12999        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13000        let text_layout_details = &self.text_layout_details(window);
13001        self.change_selections(Default::default(), window, cx, |s| {
13002            s.move_heads_with(|map, head, goal| {
13003                movement::up(map, head, goal, false, text_layout_details)
13004            })
13005        })
13006    }
13007
13008    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13009        self.take_rename(true, window, cx);
13010
13011        if self.mode.is_single_line() {
13012            cx.propagate();
13013            return;
13014        }
13015
13016        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13017
13018        let text_layout_details = &self.text_layout_details(window);
13019        let selection_count = self.selections.count();
13020        let first_selection = self.selections.first_anchor();
13021
13022        self.change_selections(Default::default(), window, cx, |s| {
13023            s.move_with(|map, selection| {
13024                if !selection.is_empty() {
13025                    selection.goal = SelectionGoal::None;
13026                }
13027                let (cursor, goal) = movement::down(
13028                    map,
13029                    selection.end,
13030                    selection.goal,
13031                    false,
13032                    text_layout_details,
13033                );
13034                selection.collapse_to(cursor, goal);
13035            });
13036        });
13037
13038        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13039        {
13040            cx.propagate();
13041        }
13042    }
13043
13044    pub fn select_page_down(
13045        &mut self,
13046        _: &SelectPageDown,
13047        window: &mut Window,
13048        cx: &mut Context<Self>,
13049    ) {
13050        let Some(row_count) = self.visible_row_count() else {
13051            return;
13052        };
13053
13054        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13055
13056        let text_layout_details = &self.text_layout_details(window);
13057
13058        self.change_selections(Default::default(), window, cx, |s| {
13059            s.move_heads_with(|map, head, goal| {
13060                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13061            })
13062        })
13063    }
13064
13065    pub fn move_page_down(
13066        &mut self,
13067        action: &MovePageDown,
13068        window: &mut Window,
13069        cx: &mut Context<Self>,
13070    ) {
13071        if self.take_rename(true, window, cx).is_some() {
13072            return;
13073        }
13074
13075        if self
13076            .context_menu
13077            .borrow_mut()
13078            .as_mut()
13079            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13080            .unwrap_or(false)
13081        {
13082            return;
13083        }
13084
13085        if matches!(self.mode, EditorMode::SingleLine) {
13086            cx.propagate();
13087            return;
13088        }
13089
13090        let Some(row_count) = self.visible_row_count() else {
13091            return;
13092        };
13093
13094        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13095
13096        let effects = if action.center_cursor {
13097            SelectionEffects::scroll(Autoscroll::center())
13098        } else {
13099            SelectionEffects::default()
13100        };
13101
13102        let text_layout_details = &self.text_layout_details(window);
13103        self.change_selections(effects, window, cx, |s| {
13104            s.move_with(|map, selection| {
13105                if !selection.is_empty() {
13106                    selection.goal = SelectionGoal::None;
13107                }
13108                let (cursor, goal) = movement::down_by_rows(
13109                    map,
13110                    selection.end,
13111                    row_count,
13112                    selection.goal,
13113                    false,
13114                    text_layout_details,
13115                );
13116                selection.collapse_to(cursor, goal);
13117            });
13118        });
13119    }
13120
13121    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13122        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13123        let text_layout_details = &self.text_layout_details(window);
13124        self.change_selections(Default::default(), window, cx, |s| {
13125            s.move_heads_with(|map, head, goal| {
13126                movement::down(map, head, goal, false, text_layout_details)
13127            })
13128        });
13129    }
13130
13131    pub fn context_menu_first(
13132        &mut self,
13133        _: &ContextMenuFirst,
13134        window: &mut Window,
13135        cx: &mut Context<Self>,
13136    ) {
13137        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13138            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13139        }
13140    }
13141
13142    pub fn context_menu_prev(
13143        &mut self,
13144        _: &ContextMenuPrevious,
13145        window: &mut Window,
13146        cx: &mut Context<Self>,
13147    ) {
13148        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13149            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13150        }
13151    }
13152
13153    pub fn context_menu_next(
13154        &mut self,
13155        _: &ContextMenuNext,
13156        window: &mut Window,
13157        cx: &mut Context<Self>,
13158    ) {
13159        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13160            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13161        }
13162    }
13163
13164    pub fn context_menu_last(
13165        &mut self,
13166        _: &ContextMenuLast,
13167        window: &mut Window,
13168        cx: &mut Context<Self>,
13169    ) {
13170        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13171            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13172        }
13173    }
13174
13175    pub fn signature_help_prev(
13176        &mut self,
13177        _: &SignatureHelpPrevious,
13178        _: &mut Window,
13179        cx: &mut Context<Self>,
13180    ) {
13181        if let Some(popover) = self.signature_help_state.popover_mut() {
13182            if popover.current_signature == 0 {
13183                popover.current_signature = popover.signatures.len() - 1;
13184            } else {
13185                popover.current_signature -= 1;
13186            }
13187            cx.notify();
13188        }
13189    }
13190
13191    pub fn signature_help_next(
13192        &mut self,
13193        _: &SignatureHelpNext,
13194        _: &mut Window,
13195        cx: &mut Context<Self>,
13196    ) {
13197        if let Some(popover) = self.signature_help_state.popover_mut() {
13198            if popover.current_signature + 1 == popover.signatures.len() {
13199                popover.current_signature = 0;
13200            } else {
13201                popover.current_signature += 1;
13202            }
13203            cx.notify();
13204        }
13205    }
13206
13207    pub fn move_to_previous_word_start(
13208        &mut self,
13209        _: &MoveToPreviousWordStart,
13210        window: &mut Window,
13211        cx: &mut Context<Self>,
13212    ) {
13213        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13214        self.change_selections(Default::default(), window, cx, |s| {
13215            s.move_cursors_with(|map, head, _| {
13216                (
13217                    movement::previous_word_start(map, head),
13218                    SelectionGoal::None,
13219                )
13220            });
13221        })
13222    }
13223
13224    pub fn move_to_previous_subword_start(
13225        &mut self,
13226        _: &MoveToPreviousSubwordStart,
13227        window: &mut Window,
13228        cx: &mut Context<Self>,
13229    ) {
13230        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13231        self.change_selections(Default::default(), window, cx, |s| {
13232            s.move_cursors_with(|map, head, _| {
13233                (
13234                    movement::previous_subword_start(map, head),
13235                    SelectionGoal::None,
13236                )
13237            });
13238        })
13239    }
13240
13241    pub fn select_to_previous_word_start(
13242        &mut self,
13243        _: &SelectToPreviousWordStart,
13244        window: &mut Window,
13245        cx: &mut Context<Self>,
13246    ) {
13247        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13248        self.change_selections(Default::default(), window, cx, |s| {
13249            s.move_heads_with(|map, head, _| {
13250                (
13251                    movement::previous_word_start(map, head),
13252                    SelectionGoal::None,
13253                )
13254            });
13255        })
13256    }
13257
13258    pub fn select_to_previous_subword_start(
13259        &mut self,
13260        _: &SelectToPreviousSubwordStart,
13261        window: &mut Window,
13262        cx: &mut Context<Self>,
13263    ) {
13264        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13265        self.change_selections(Default::default(), window, cx, |s| {
13266            s.move_heads_with(|map, head, _| {
13267                (
13268                    movement::previous_subword_start(map, head),
13269                    SelectionGoal::None,
13270                )
13271            });
13272        })
13273    }
13274
13275    pub fn delete_to_previous_word_start(
13276        &mut self,
13277        action: &DeleteToPreviousWordStart,
13278        window: &mut Window,
13279        cx: &mut Context<Self>,
13280    ) {
13281        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13282        self.transact(window, cx, |this, window, cx| {
13283            this.select_autoclose_pair(window, cx);
13284            this.change_selections(Default::default(), window, cx, |s| {
13285                s.move_with(|map, selection| {
13286                    if selection.is_empty() {
13287                        let mut cursor = if action.ignore_newlines {
13288                            movement::previous_word_start(map, selection.head())
13289                        } else {
13290                            movement::previous_word_start_or_newline(map, selection.head())
13291                        };
13292                        cursor = movement::adjust_greedy_deletion(
13293                            map,
13294                            selection.head(),
13295                            cursor,
13296                            action.ignore_brackets,
13297                        );
13298                        selection.set_head(cursor, SelectionGoal::None);
13299                    }
13300                });
13301            });
13302            this.insert("", window, cx);
13303        });
13304    }
13305
13306    pub fn delete_to_previous_subword_start(
13307        &mut self,
13308        _: &DeleteToPreviousSubwordStart,
13309        window: &mut Window,
13310        cx: &mut Context<Self>,
13311    ) {
13312        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13313        self.transact(window, cx, |this, window, cx| {
13314            this.select_autoclose_pair(window, cx);
13315            this.change_selections(Default::default(), window, cx, |s| {
13316                s.move_with(|map, selection| {
13317                    if selection.is_empty() {
13318                        let mut cursor = movement::previous_subword_start(map, selection.head());
13319                        cursor =
13320                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13321                        selection.set_head(cursor, SelectionGoal::None);
13322                    }
13323                });
13324            });
13325            this.insert("", window, cx);
13326        });
13327    }
13328
13329    pub fn move_to_next_word_end(
13330        &mut self,
13331        _: &MoveToNextWordEnd,
13332        window: &mut Window,
13333        cx: &mut Context<Self>,
13334    ) {
13335        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13336        self.change_selections(Default::default(), window, cx, |s| {
13337            s.move_cursors_with(|map, head, _| {
13338                (movement::next_word_end(map, head), SelectionGoal::None)
13339            });
13340        })
13341    }
13342
13343    pub fn move_to_next_subword_end(
13344        &mut self,
13345        _: &MoveToNextSubwordEnd,
13346        window: &mut Window,
13347        cx: &mut Context<Self>,
13348    ) {
13349        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13350        self.change_selections(Default::default(), window, cx, |s| {
13351            s.move_cursors_with(|map, head, _| {
13352                (movement::next_subword_end(map, head), SelectionGoal::None)
13353            });
13354        })
13355    }
13356
13357    pub fn select_to_next_word_end(
13358        &mut self,
13359        _: &SelectToNextWordEnd,
13360        window: &mut Window,
13361        cx: &mut Context<Self>,
13362    ) {
13363        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13364        self.change_selections(Default::default(), window, cx, |s| {
13365            s.move_heads_with(|map, head, _| {
13366                (movement::next_word_end(map, head), SelectionGoal::None)
13367            });
13368        })
13369    }
13370
13371    pub fn select_to_next_subword_end(
13372        &mut self,
13373        _: &SelectToNextSubwordEnd,
13374        window: &mut Window,
13375        cx: &mut Context<Self>,
13376    ) {
13377        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13378        self.change_selections(Default::default(), window, cx, |s| {
13379            s.move_heads_with(|map, head, _| {
13380                (movement::next_subword_end(map, head), SelectionGoal::None)
13381            });
13382        })
13383    }
13384
13385    pub fn delete_to_next_word_end(
13386        &mut self,
13387        action: &DeleteToNextWordEnd,
13388        window: &mut Window,
13389        cx: &mut Context<Self>,
13390    ) {
13391        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13392        self.transact(window, cx, |this, window, cx| {
13393            this.change_selections(Default::default(), window, cx, |s| {
13394                s.move_with(|map, selection| {
13395                    if selection.is_empty() {
13396                        let mut cursor = if action.ignore_newlines {
13397                            movement::next_word_end(map, selection.head())
13398                        } else {
13399                            movement::next_word_end_or_newline(map, selection.head())
13400                        };
13401                        cursor = movement::adjust_greedy_deletion(
13402                            map,
13403                            selection.head(),
13404                            cursor,
13405                            action.ignore_brackets,
13406                        );
13407                        selection.set_head(cursor, SelectionGoal::None);
13408                    }
13409                });
13410            });
13411            this.insert("", window, cx);
13412        });
13413    }
13414
13415    pub fn delete_to_next_subword_end(
13416        &mut self,
13417        _: &DeleteToNextSubwordEnd,
13418        window: &mut Window,
13419        cx: &mut Context<Self>,
13420    ) {
13421        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13422        self.transact(window, cx, |this, window, cx| {
13423            this.change_selections(Default::default(), window, cx, |s| {
13424                s.move_with(|map, selection| {
13425                    if selection.is_empty() {
13426                        let mut cursor = movement::next_subword_end(map, selection.head());
13427                        cursor =
13428                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13429                        selection.set_head(cursor, SelectionGoal::None);
13430                    }
13431                });
13432            });
13433            this.insert("", window, cx);
13434        });
13435    }
13436
13437    pub fn move_to_beginning_of_line(
13438        &mut self,
13439        action: &MoveToBeginningOfLine,
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::indented_line_beginning(
13448                        map,
13449                        head,
13450                        action.stop_at_soft_wraps,
13451                        action.stop_at_indent,
13452                    ),
13453                    SelectionGoal::None,
13454                )
13455            });
13456        })
13457    }
13458
13459    pub fn select_to_beginning_of_line(
13460        &mut self,
13461        action: &SelectToBeginningOfLine,
13462        window: &mut Window,
13463        cx: &mut Context<Self>,
13464    ) {
13465        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13466        self.change_selections(Default::default(), window, cx, |s| {
13467            s.move_heads_with(|map, head, _| {
13468                (
13469                    movement::indented_line_beginning(
13470                        map,
13471                        head,
13472                        action.stop_at_soft_wraps,
13473                        action.stop_at_indent,
13474                    ),
13475                    SelectionGoal::None,
13476                )
13477            });
13478        });
13479    }
13480
13481    pub fn delete_to_beginning_of_line(
13482        &mut self,
13483        action: &DeleteToBeginningOfLine,
13484        window: &mut Window,
13485        cx: &mut Context<Self>,
13486    ) {
13487        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13488        self.transact(window, cx, |this, window, cx| {
13489            this.change_selections(Default::default(), window, cx, |s| {
13490                s.move_with(|_, selection| {
13491                    selection.reversed = true;
13492                });
13493            });
13494
13495            this.select_to_beginning_of_line(
13496                &SelectToBeginningOfLine {
13497                    stop_at_soft_wraps: false,
13498                    stop_at_indent: action.stop_at_indent,
13499                },
13500                window,
13501                cx,
13502            );
13503            this.backspace(&Backspace, window, cx);
13504        });
13505    }
13506
13507    pub fn move_to_end_of_line(
13508        &mut self,
13509        action: &MoveToEndOfLine,
13510        window: &mut Window,
13511        cx: &mut Context<Self>,
13512    ) {
13513        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13514        self.change_selections(Default::default(), window, cx, |s| {
13515            s.move_cursors_with(|map, head, _| {
13516                (
13517                    movement::line_end(map, head, action.stop_at_soft_wraps),
13518                    SelectionGoal::None,
13519                )
13520            });
13521        })
13522    }
13523
13524    pub fn select_to_end_of_line(
13525        &mut self,
13526        action: &SelectToEndOfLine,
13527        window: &mut Window,
13528        cx: &mut Context<Self>,
13529    ) {
13530        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13531        self.change_selections(Default::default(), window, cx, |s| {
13532            s.move_heads_with(|map, head, _| {
13533                (
13534                    movement::line_end(map, head, action.stop_at_soft_wraps),
13535                    SelectionGoal::None,
13536                )
13537            });
13538        })
13539    }
13540
13541    pub fn delete_to_end_of_line(
13542        &mut self,
13543        _: &DeleteToEndOfLine,
13544        window: &mut Window,
13545        cx: &mut Context<Self>,
13546    ) {
13547        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13548        self.transact(window, cx, |this, window, cx| {
13549            this.select_to_end_of_line(
13550                &SelectToEndOfLine {
13551                    stop_at_soft_wraps: false,
13552                },
13553                window,
13554                cx,
13555            );
13556            this.delete(&Delete, window, cx);
13557        });
13558    }
13559
13560    pub fn cut_to_end_of_line(
13561        &mut self,
13562        action: &CutToEndOfLine,
13563        window: &mut Window,
13564        cx: &mut Context<Self>,
13565    ) {
13566        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13567        self.transact(window, cx, |this, window, cx| {
13568            this.select_to_end_of_line(
13569                &SelectToEndOfLine {
13570                    stop_at_soft_wraps: false,
13571                },
13572                window,
13573                cx,
13574            );
13575            if !action.stop_at_newlines {
13576                this.change_selections(Default::default(), window, cx, |s| {
13577                    s.move_with(|_, sel| {
13578                        if sel.is_empty() {
13579                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13580                        }
13581                    });
13582                });
13583            }
13584            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13585            let item = this.cut_common(false, window, cx);
13586            cx.write_to_clipboard(item);
13587        });
13588    }
13589
13590    pub fn move_to_start_of_paragraph(
13591        &mut self,
13592        _: &MoveToStartOfParagraph,
13593        window: &mut Window,
13594        cx: &mut Context<Self>,
13595    ) {
13596        if matches!(self.mode, EditorMode::SingleLine) {
13597            cx.propagate();
13598            return;
13599        }
13600        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13601        self.change_selections(Default::default(), window, cx, |s| {
13602            s.move_with(|map, selection| {
13603                selection.collapse_to(
13604                    movement::start_of_paragraph(map, selection.head(), 1),
13605                    SelectionGoal::None,
13606                )
13607            });
13608        })
13609    }
13610
13611    pub fn move_to_end_of_paragraph(
13612        &mut self,
13613        _: &MoveToEndOfParagraph,
13614        window: &mut Window,
13615        cx: &mut Context<Self>,
13616    ) {
13617        if matches!(self.mode, EditorMode::SingleLine) {
13618            cx.propagate();
13619            return;
13620        }
13621        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13622        self.change_selections(Default::default(), window, cx, |s| {
13623            s.move_with(|map, selection| {
13624                selection.collapse_to(
13625                    movement::end_of_paragraph(map, selection.head(), 1),
13626                    SelectionGoal::None,
13627                )
13628            });
13629        })
13630    }
13631
13632    pub fn select_to_start_of_paragraph(
13633        &mut self,
13634        _: &SelectToStartOfParagraph,
13635        window: &mut Window,
13636        cx: &mut Context<Self>,
13637    ) {
13638        if matches!(self.mode, EditorMode::SingleLine) {
13639            cx.propagate();
13640            return;
13641        }
13642        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13643        self.change_selections(Default::default(), window, cx, |s| {
13644            s.move_heads_with(|map, head, _| {
13645                (
13646                    movement::start_of_paragraph(map, head, 1),
13647                    SelectionGoal::None,
13648                )
13649            });
13650        })
13651    }
13652
13653    pub fn select_to_end_of_paragraph(
13654        &mut self,
13655        _: &SelectToEndOfParagraph,
13656        window: &mut Window,
13657        cx: &mut Context<Self>,
13658    ) {
13659        if matches!(self.mode, EditorMode::SingleLine) {
13660            cx.propagate();
13661            return;
13662        }
13663        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13664        self.change_selections(Default::default(), window, cx, |s| {
13665            s.move_heads_with(|map, head, _| {
13666                (
13667                    movement::end_of_paragraph(map, head, 1),
13668                    SelectionGoal::None,
13669                )
13670            });
13671        })
13672    }
13673
13674    pub fn move_to_start_of_excerpt(
13675        &mut self,
13676        _: &MoveToStartOfExcerpt,
13677        window: &mut Window,
13678        cx: &mut Context<Self>,
13679    ) {
13680        if matches!(self.mode, EditorMode::SingleLine) {
13681            cx.propagate();
13682            return;
13683        }
13684        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13685        self.change_selections(Default::default(), window, cx, |s| {
13686            s.move_with(|map, selection| {
13687                selection.collapse_to(
13688                    movement::start_of_excerpt(
13689                        map,
13690                        selection.head(),
13691                        workspace::searchable::Direction::Prev,
13692                    ),
13693                    SelectionGoal::None,
13694                )
13695            });
13696        })
13697    }
13698
13699    pub fn move_to_start_of_next_excerpt(
13700        &mut self,
13701        _: &MoveToStartOfNextExcerpt,
13702        window: &mut Window,
13703        cx: &mut Context<Self>,
13704    ) {
13705        if matches!(self.mode, EditorMode::SingleLine) {
13706            cx.propagate();
13707            return;
13708        }
13709
13710        self.change_selections(Default::default(), window, cx, |s| {
13711            s.move_with(|map, selection| {
13712                selection.collapse_to(
13713                    movement::start_of_excerpt(
13714                        map,
13715                        selection.head(),
13716                        workspace::searchable::Direction::Next,
13717                    ),
13718                    SelectionGoal::None,
13719                )
13720            });
13721        })
13722    }
13723
13724    pub fn move_to_end_of_excerpt(
13725        &mut self,
13726        _: &MoveToEndOfExcerpt,
13727        window: &mut Window,
13728        cx: &mut Context<Self>,
13729    ) {
13730        if matches!(self.mode, EditorMode::SingleLine) {
13731            cx.propagate();
13732            return;
13733        }
13734        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13735        self.change_selections(Default::default(), window, cx, |s| {
13736            s.move_with(|map, selection| {
13737                selection.collapse_to(
13738                    movement::end_of_excerpt(
13739                        map,
13740                        selection.head(),
13741                        workspace::searchable::Direction::Next,
13742                    ),
13743                    SelectionGoal::None,
13744                )
13745            });
13746        })
13747    }
13748
13749    pub fn move_to_end_of_previous_excerpt(
13750        &mut self,
13751        _: &MoveToEndOfPreviousExcerpt,
13752        window: &mut Window,
13753        cx: &mut Context<Self>,
13754    ) {
13755        if matches!(self.mode, EditorMode::SingleLine) {
13756            cx.propagate();
13757            return;
13758        }
13759        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13760        self.change_selections(Default::default(), window, cx, |s| {
13761            s.move_with(|map, selection| {
13762                selection.collapse_to(
13763                    movement::end_of_excerpt(
13764                        map,
13765                        selection.head(),
13766                        workspace::searchable::Direction::Prev,
13767                    ),
13768                    SelectionGoal::None,
13769                )
13770            });
13771        })
13772    }
13773
13774    pub fn select_to_start_of_excerpt(
13775        &mut self,
13776        _: &SelectToStartOfExcerpt,
13777        window: &mut Window,
13778        cx: &mut Context<Self>,
13779    ) {
13780        if matches!(self.mode, EditorMode::SingleLine) {
13781            cx.propagate();
13782            return;
13783        }
13784        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13785        self.change_selections(Default::default(), window, cx, |s| {
13786            s.move_heads_with(|map, head, _| {
13787                (
13788                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13789                    SelectionGoal::None,
13790                )
13791            });
13792        })
13793    }
13794
13795    pub fn select_to_start_of_next_excerpt(
13796        &mut self,
13797        _: &SelectToStartOfNextExcerpt,
13798        window: &mut Window,
13799        cx: &mut Context<Self>,
13800    ) {
13801        if matches!(self.mode, EditorMode::SingleLine) {
13802            cx.propagate();
13803            return;
13804        }
13805        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13806        self.change_selections(Default::default(), window, cx, |s| {
13807            s.move_heads_with(|map, head, _| {
13808                (
13809                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13810                    SelectionGoal::None,
13811                )
13812            });
13813        })
13814    }
13815
13816    pub fn select_to_end_of_excerpt(
13817        &mut self,
13818        _: &SelectToEndOfExcerpt,
13819        window: &mut Window,
13820        cx: &mut Context<Self>,
13821    ) {
13822        if matches!(self.mode, EditorMode::SingleLine) {
13823            cx.propagate();
13824            return;
13825        }
13826        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13827        self.change_selections(Default::default(), window, cx, |s| {
13828            s.move_heads_with(|map, head, _| {
13829                (
13830                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13831                    SelectionGoal::None,
13832                )
13833            });
13834        })
13835    }
13836
13837    pub fn select_to_end_of_previous_excerpt(
13838        &mut self,
13839        _: &SelectToEndOfPreviousExcerpt,
13840        window: &mut Window,
13841        cx: &mut Context<Self>,
13842    ) {
13843        if matches!(self.mode, EditorMode::SingleLine) {
13844            cx.propagate();
13845            return;
13846        }
13847        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13848        self.change_selections(Default::default(), window, cx, |s| {
13849            s.move_heads_with(|map, head, _| {
13850                (
13851                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13852                    SelectionGoal::None,
13853                )
13854            });
13855        })
13856    }
13857
13858    pub fn move_to_beginning(
13859        &mut self,
13860        _: &MoveToBeginning,
13861        window: &mut Window,
13862        cx: &mut Context<Self>,
13863    ) {
13864        if matches!(self.mode, EditorMode::SingleLine) {
13865            cx.propagate();
13866            return;
13867        }
13868        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13869        self.change_selections(Default::default(), window, cx, |s| {
13870            s.select_ranges(vec![0..0]);
13871        });
13872    }
13873
13874    pub fn select_to_beginning(
13875        &mut self,
13876        _: &SelectToBeginning,
13877        window: &mut Window,
13878        cx: &mut Context<Self>,
13879    ) {
13880        let mut selection = self.selections.last::<Point>(cx);
13881        selection.set_head(Point::zero(), SelectionGoal::None);
13882        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13883        self.change_selections(Default::default(), window, cx, |s| {
13884            s.select(vec![selection]);
13885        });
13886    }
13887
13888    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13889        if matches!(self.mode, EditorMode::SingleLine) {
13890            cx.propagate();
13891            return;
13892        }
13893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13894        let cursor = self.buffer.read(cx).read(cx).len();
13895        self.change_selections(Default::default(), window, cx, |s| {
13896            s.select_ranges(vec![cursor..cursor])
13897        });
13898    }
13899
13900    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13901        self.nav_history = nav_history;
13902    }
13903
13904    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13905        self.nav_history.as_ref()
13906    }
13907
13908    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13909        self.push_to_nav_history(
13910            self.selections.newest_anchor().head(),
13911            None,
13912            false,
13913            true,
13914            cx,
13915        );
13916    }
13917
13918    fn push_to_nav_history(
13919        &mut self,
13920        cursor_anchor: Anchor,
13921        new_position: Option<Point>,
13922        is_deactivate: bool,
13923        always: bool,
13924        cx: &mut Context<Self>,
13925    ) {
13926        if let Some(nav_history) = self.nav_history.as_mut() {
13927            let buffer = self.buffer.read(cx).read(cx);
13928            let cursor_position = cursor_anchor.to_point(&buffer);
13929            let scroll_state = self.scroll_manager.anchor();
13930            let scroll_top_row = scroll_state.top_row(&buffer);
13931            drop(buffer);
13932
13933            if let Some(new_position) = new_position {
13934                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13935                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13936                    return;
13937                }
13938            }
13939
13940            nav_history.push(
13941                Some(NavigationData {
13942                    cursor_anchor,
13943                    cursor_position,
13944                    scroll_anchor: scroll_state,
13945                    scroll_top_row,
13946                }),
13947                cx,
13948            );
13949            cx.emit(EditorEvent::PushedToNavHistory {
13950                anchor: cursor_anchor,
13951                is_deactivate,
13952            })
13953        }
13954    }
13955
13956    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13957        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13958        let buffer = self.buffer.read(cx).snapshot(cx);
13959        let mut selection = self.selections.first::<usize>(cx);
13960        selection.set_head(buffer.len(), SelectionGoal::None);
13961        self.change_selections(Default::default(), window, cx, |s| {
13962            s.select(vec![selection]);
13963        });
13964    }
13965
13966    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13967        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13968        let end = self.buffer.read(cx).read(cx).len();
13969        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13970            s.select_ranges(vec![0..end]);
13971        });
13972    }
13973
13974    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13975        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13976        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13977        let mut selections = self.selections.all::<Point>(cx);
13978        let max_point = display_map.buffer_snapshot.max_point();
13979        for selection in &mut selections {
13980            let rows = selection.spanned_rows(true, &display_map);
13981            selection.start = Point::new(rows.start.0, 0);
13982            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13983            selection.reversed = false;
13984        }
13985        self.change_selections(Default::default(), window, cx, |s| {
13986            s.select(selections);
13987        });
13988    }
13989
13990    pub fn split_selection_into_lines(
13991        &mut self,
13992        action: &SplitSelectionIntoLines,
13993        window: &mut Window,
13994        cx: &mut Context<Self>,
13995    ) {
13996        let selections = self
13997            .selections
13998            .all::<Point>(cx)
13999            .into_iter()
14000            .map(|selection| selection.start..selection.end)
14001            .collect::<Vec<_>>();
14002        self.unfold_ranges(&selections, true, true, cx);
14003
14004        let mut new_selection_ranges = Vec::new();
14005        {
14006            let buffer = self.buffer.read(cx).read(cx);
14007            for selection in selections {
14008                for row in selection.start.row..selection.end.row {
14009                    let line_start = Point::new(row, 0);
14010                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14011
14012                    if action.keep_selections {
14013                        // Keep the selection range for each line
14014                        let selection_start = if row == selection.start.row {
14015                            selection.start
14016                        } else {
14017                            line_start
14018                        };
14019                        new_selection_ranges.push(selection_start..line_end);
14020                    } else {
14021                        // Collapse to cursor at end of line
14022                        new_selection_ranges.push(line_end..line_end);
14023                    }
14024                }
14025
14026                let is_multiline_selection = selection.start.row != selection.end.row;
14027                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14028                // so this action feels more ergonomic when paired with other selection operations
14029                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14030                if !should_skip_last {
14031                    if action.keep_selections {
14032                        if is_multiline_selection {
14033                            let line_start = Point::new(selection.end.row, 0);
14034                            new_selection_ranges.push(line_start..selection.end);
14035                        } else {
14036                            new_selection_ranges.push(selection.start..selection.end);
14037                        }
14038                    } else {
14039                        new_selection_ranges.push(selection.end..selection.end);
14040                    }
14041                }
14042            }
14043        }
14044        self.change_selections(Default::default(), window, cx, |s| {
14045            s.select_ranges(new_selection_ranges);
14046        });
14047    }
14048
14049    pub fn add_selection_above(
14050        &mut self,
14051        _: &AddSelectionAbove,
14052        window: &mut Window,
14053        cx: &mut Context<Self>,
14054    ) {
14055        self.add_selection(true, window, cx);
14056    }
14057
14058    pub fn add_selection_below(
14059        &mut self,
14060        _: &AddSelectionBelow,
14061        window: &mut Window,
14062        cx: &mut Context<Self>,
14063    ) {
14064        self.add_selection(false, window, cx);
14065    }
14066
14067    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14068        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14069
14070        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14071        let all_selections = self.selections.all::<Point>(cx);
14072        let text_layout_details = self.text_layout_details(window);
14073
14074        let (mut columnar_selections, new_selections_to_columnarize) = {
14075            if let Some(state) = self.add_selections_state.as_ref() {
14076                let columnar_selection_ids: HashSet<_> = state
14077                    .groups
14078                    .iter()
14079                    .flat_map(|group| group.stack.iter())
14080                    .copied()
14081                    .collect();
14082
14083                all_selections
14084                    .into_iter()
14085                    .partition(|s| columnar_selection_ids.contains(&s.id))
14086            } else {
14087                (Vec::new(), all_selections)
14088            }
14089        };
14090
14091        let mut state = self
14092            .add_selections_state
14093            .take()
14094            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14095
14096        for selection in new_selections_to_columnarize {
14097            let range = selection.display_range(&display_map).sorted();
14098            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14099            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14100            let positions = start_x.min(end_x)..start_x.max(end_x);
14101            let mut stack = Vec::new();
14102            for row in range.start.row().0..=range.end.row().0 {
14103                if let Some(selection) = self.selections.build_columnar_selection(
14104                    &display_map,
14105                    DisplayRow(row),
14106                    &positions,
14107                    selection.reversed,
14108                    &text_layout_details,
14109                ) {
14110                    stack.push(selection.id);
14111                    columnar_selections.push(selection);
14112                }
14113            }
14114            if !stack.is_empty() {
14115                if above {
14116                    stack.reverse();
14117                }
14118                state.groups.push(AddSelectionsGroup { above, stack });
14119            }
14120        }
14121
14122        let mut final_selections = Vec::new();
14123        let end_row = if above {
14124            DisplayRow(0)
14125        } else {
14126            display_map.max_point().row()
14127        };
14128
14129        let mut last_added_item_per_group = HashMap::default();
14130        for group in state.groups.iter_mut() {
14131            if let Some(last_id) = group.stack.last() {
14132                last_added_item_per_group.insert(*last_id, group);
14133            }
14134        }
14135
14136        for selection in columnar_selections {
14137            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14138                if above == group.above {
14139                    let range = selection.display_range(&display_map).sorted();
14140                    debug_assert_eq!(range.start.row(), range.end.row());
14141                    let mut row = range.start.row();
14142                    let positions =
14143                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14144                            px(start)..px(end)
14145                        } else {
14146                            let start_x =
14147                                display_map.x_for_display_point(range.start, &text_layout_details);
14148                            let end_x =
14149                                display_map.x_for_display_point(range.end, &text_layout_details);
14150                            start_x.min(end_x)..start_x.max(end_x)
14151                        };
14152
14153                    let mut maybe_new_selection = None;
14154                    while row != end_row {
14155                        if above {
14156                            row.0 -= 1;
14157                        } else {
14158                            row.0 += 1;
14159                        }
14160                        if let Some(new_selection) = self.selections.build_columnar_selection(
14161                            &display_map,
14162                            row,
14163                            &positions,
14164                            selection.reversed,
14165                            &text_layout_details,
14166                        ) {
14167                            maybe_new_selection = Some(new_selection);
14168                            break;
14169                        }
14170                    }
14171
14172                    if let Some(new_selection) = maybe_new_selection {
14173                        group.stack.push(new_selection.id);
14174                        if above {
14175                            final_selections.push(new_selection);
14176                            final_selections.push(selection);
14177                        } else {
14178                            final_selections.push(selection);
14179                            final_selections.push(new_selection);
14180                        }
14181                    } else {
14182                        final_selections.push(selection);
14183                    }
14184                } else {
14185                    group.stack.pop();
14186                }
14187            } else {
14188                final_selections.push(selection);
14189            }
14190        }
14191
14192        self.change_selections(Default::default(), window, cx, |s| {
14193            s.select(final_selections);
14194        });
14195
14196        let final_selection_ids: HashSet<_> = self
14197            .selections
14198            .all::<Point>(cx)
14199            .iter()
14200            .map(|s| s.id)
14201            .collect();
14202        state.groups.retain_mut(|group| {
14203            // selections might get merged above so we remove invalid items from stacks
14204            group.stack.retain(|id| final_selection_ids.contains(id));
14205
14206            // single selection in stack can be treated as initial state
14207            group.stack.len() > 1
14208        });
14209
14210        if !state.groups.is_empty() {
14211            self.add_selections_state = Some(state);
14212        }
14213    }
14214
14215    fn select_match_ranges(
14216        &mut self,
14217        range: Range<usize>,
14218        reversed: bool,
14219        replace_newest: bool,
14220        auto_scroll: Option<Autoscroll>,
14221        window: &mut Window,
14222        cx: &mut Context<Editor>,
14223    ) {
14224        self.unfold_ranges(
14225            std::slice::from_ref(&range),
14226            false,
14227            auto_scroll.is_some(),
14228            cx,
14229        );
14230        let effects = if let Some(scroll) = auto_scroll {
14231            SelectionEffects::scroll(scroll)
14232        } else {
14233            SelectionEffects::no_scroll()
14234        };
14235        self.change_selections(effects, window, cx, |s| {
14236            if replace_newest {
14237                s.delete(s.newest_anchor().id);
14238            }
14239            if reversed {
14240                s.insert_range(range.end..range.start);
14241            } else {
14242                s.insert_range(range);
14243            }
14244        });
14245    }
14246
14247    pub fn select_next_match_internal(
14248        &mut self,
14249        display_map: &DisplaySnapshot,
14250        replace_newest: bool,
14251        autoscroll: Option<Autoscroll>,
14252        window: &mut Window,
14253        cx: &mut Context<Self>,
14254    ) -> Result<()> {
14255        let buffer = &display_map.buffer_snapshot;
14256        let mut selections = self.selections.all::<usize>(cx);
14257        if let Some(mut select_next_state) = self.select_next_state.take() {
14258            let query = &select_next_state.query;
14259            if !select_next_state.done {
14260                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14261                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14262                let mut next_selected_range = None;
14263
14264                let bytes_after_last_selection =
14265                    buffer.bytes_in_range(last_selection.end..buffer.len());
14266                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14267                let query_matches = query
14268                    .stream_find_iter(bytes_after_last_selection)
14269                    .map(|result| (last_selection.end, result))
14270                    .chain(
14271                        query
14272                            .stream_find_iter(bytes_before_first_selection)
14273                            .map(|result| (0, result)),
14274                    );
14275
14276                for (start_offset, query_match) in query_matches {
14277                    let query_match = query_match.unwrap(); // can only fail due to I/O
14278                    let offset_range =
14279                        start_offset + query_match.start()..start_offset + query_match.end();
14280
14281                    if !select_next_state.wordwise
14282                        || (!buffer.is_inside_word(offset_range.start, None)
14283                            && !buffer.is_inside_word(offset_range.end, None))
14284                    {
14285                        // TODO: This is n^2, because we might check all the selections
14286                        if !selections
14287                            .iter()
14288                            .any(|selection| selection.range().overlaps(&offset_range))
14289                        {
14290                            next_selected_range = Some(offset_range);
14291                            break;
14292                        }
14293                    }
14294                }
14295
14296                if let Some(next_selected_range) = next_selected_range {
14297                    self.select_match_ranges(
14298                        next_selected_range,
14299                        last_selection.reversed,
14300                        replace_newest,
14301                        autoscroll,
14302                        window,
14303                        cx,
14304                    );
14305                } else {
14306                    select_next_state.done = true;
14307                }
14308            }
14309
14310            self.select_next_state = Some(select_next_state);
14311        } else {
14312            let mut only_carets = true;
14313            let mut same_text_selected = true;
14314            let mut selected_text = None;
14315
14316            let mut selections_iter = selections.iter().peekable();
14317            while let Some(selection) = selections_iter.next() {
14318                if selection.start != selection.end {
14319                    only_carets = false;
14320                }
14321
14322                if same_text_selected {
14323                    if selected_text.is_none() {
14324                        selected_text =
14325                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14326                    }
14327
14328                    if let Some(next_selection) = selections_iter.peek() {
14329                        if next_selection.range().len() == selection.range().len() {
14330                            let next_selected_text = buffer
14331                                .text_for_range(next_selection.range())
14332                                .collect::<String>();
14333                            if Some(next_selected_text) != selected_text {
14334                                same_text_selected = false;
14335                                selected_text = None;
14336                            }
14337                        } else {
14338                            same_text_selected = false;
14339                            selected_text = None;
14340                        }
14341                    }
14342                }
14343            }
14344
14345            if only_carets {
14346                for selection in &mut selections {
14347                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14348                    selection.start = word_range.start;
14349                    selection.end = word_range.end;
14350                    selection.goal = SelectionGoal::None;
14351                    selection.reversed = false;
14352                    self.select_match_ranges(
14353                        selection.start..selection.end,
14354                        selection.reversed,
14355                        replace_newest,
14356                        autoscroll,
14357                        window,
14358                        cx,
14359                    );
14360                }
14361
14362                if selections.len() == 1 {
14363                    let selection = selections
14364                        .last()
14365                        .expect("ensured that there's only one selection");
14366                    let query = buffer
14367                        .text_for_range(selection.start..selection.end)
14368                        .collect::<String>();
14369                    let is_empty = query.is_empty();
14370                    let select_state = SelectNextState {
14371                        query: AhoCorasick::new(&[query])?,
14372                        wordwise: true,
14373                        done: is_empty,
14374                    };
14375                    self.select_next_state = Some(select_state);
14376                } else {
14377                    self.select_next_state = None;
14378                }
14379            } else if let Some(selected_text) = selected_text {
14380                self.select_next_state = Some(SelectNextState {
14381                    query: AhoCorasick::new(&[selected_text])?,
14382                    wordwise: false,
14383                    done: false,
14384                });
14385                self.select_next_match_internal(
14386                    display_map,
14387                    replace_newest,
14388                    autoscroll,
14389                    window,
14390                    cx,
14391                )?;
14392            }
14393        }
14394        Ok(())
14395    }
14396
14397    pub fn select_all_matches(
14398        &mut self,
14399        _action: &SelectAllMatches,
14400        window: &mut Window,
14401        cx: &mut Context<Self>,
14402    ) -> Result<()> {
14403        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14404
14405        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14406
14407        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14408        let Some(select_next_state) = self.select_next_state.as_mut() else {
14409            return Ok(());
14410        };
14411        if select_next_state.done {
14412            return Ok(());
14413        }
14414
14415        let mut new_selections = Vec::new();
14416
14417        let reversed = self.selections.oldest::<usize>(cx).reversed;
14418        let buffer = &display_map.buffer_snapshot;
14419        let query_matches = select_next_state
14420            .query
14421            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14422
14423        for query_match in query_matches.into_iter() {
14424            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14425            let offset_range = if reversed {
14426                query_match.end()..query_match.start()
14427            } else {
14428                query_match.start()..query_match.end()
14429            };
14430
14431            if !select_next_state.wordwise
14432                || (!buffer.is_inside_word(offset_range.start, None)
14433                    && !buffer.is_inside_word(offset_range.end, None))
14434            {
14435                new_selections.push(offset_range.start..offset_range.end);
14436            }
14437        }
14438
14439        select_next_state.done = true;
14440
14441        if new_selections.is_empty() {
14442            log::error!("bug: new_selections is empty in select_all_matches");
14443            return Ok(());
14444        }
14445
14446        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14447        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14448            selections.select_ranges(new_selections)
14449        });
14450
14451        Ok(())
14452    }
14453
14454    pub fn select_next(
14455        &mut self,
14456        action: &SelectNext,
14457        window: &mut Window,
14458        cx: &mut Context<Self>,
14459    ) -> Result<()> {
14460        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14461        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14462        self.select_next_match_internal(
14463            &display_map,
14464            action.replace_newest,
14465            Some(Autoscroll::newest()),
14466            window,
14467            cx,
14468        )?;
14469        Ok(())
14470    }
14471
14472    pub fn select_previous(
14473        &mut self,
14474        action: &SelectPrevious,
14475        window: &mut Window,
14476        cx: &mut Context<Self>,
14477    ) -> Result<()> {
14478        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14479        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14480        let buffer = &display_map.buffer_snapshot;
14481        let mut selections = self.selections.all::<usize>(cx);
14482        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14483            let query = &select_prev_state.query;
14484            if !select_prev_state.done {
14485                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14486                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14487                let mut next_selected_range = None;
14488                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14489                let bytes_before_last_selection =
14490                    buffer.reversed_bytes_in_range(0..last_selection.start);
14491                let bytes_after_first_selection =
14492                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14493                let query_matches = query
14494                    .stream_find_iter(bytes_before_last_selection)
14495                    .map(|result| (last_selection.start, result))
14496                    .chain(
14497                        query
14498                            .stream_find_iter(bytes_after_first_selection)
14499                            .map(|result| (buffer.len(), result)),
14500                    );
14501                for (end_offset, query_match) in query_matches {
14502                    let query_match = query_match.unwrap(); // can only fail due to I/O
14503                    let offset_range =
14504                        end_offset - query_match.end()..end_offset - query_match.start();
14505
14506                    if !select_prev_state.wordwise
14507                        || (!buffer.is_inside_word(offset_range.start, None)
14508                            && !buffer.is_inside_word(offset_range.end, None))
14509                    {
14510                        next_selected_range = Some(offset_range);
14511                        break;
14512                    }
14513                }
14514
14515                if let Some(next_selected_range) = next_selected_range {
14516                    self.select_match_ranges(
14517                        next_selected_range,
14518                        last_selection.reversed,
14519                        action.replace_newest,
14520                        Some(Autoscroll::newest()),
14521                        window,
14522                        cx,
14523                    );
14524                } else {
14525                    select_prev_state.done = true;
14526                }
14527            }
14528
14529            self.select_prev_state = Some(select_prev_state);
14530        } else {
14531            let mut only_carets = true;
14532            let mut same_text_selected = true;
14533            let mut selected_text = None;
14534
14535            let mut selections_iter = selections.iter().peekable();
14536            while let Some(selection) = selections_iter.next() {
14537                if selection.start != selection.end {
14538                    only_carets = false;
14539                }
14540
14541                if same_text_selected {
14542                    if selected_text.is_none() {
14543                        selected_text =
14544                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14545                    }
14546
14547                    if let Some(next_selection) = selections_iter.peek() {
14548                        if next_selection.range().len() == selection.range().len() {
14549                            let next_selected_text = buffer
14550                                .text_for_range(next_selection.range())
14551                                .collect::<String>();
14552                            if Some(next_selected_text) != selected_text {
14553                                same_text_selected = false;
14554                                selected_text = None;
14555                            }
14556                        } else {
14557                            same_text_selected = false;
14558                            selected_text = None;
14559                        }
14560                    }
14561                }
14562            }
14563
14564            if only_carets {
14565                for selection in &mut selections {
14566                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14567                    selection.start = word_range.start;
14568                    selection.end = word_range.end;
14569                    selection.goal = SelectionGoal::None;
14570                    selection.reversed = false;
14571                    self.select_match_ranges(
14572                        selection.start..selection.end,
14573                        selection.reversed,
14574                        action.replace_newest,
14575                        Some(Autoscroll::newest()),
14576                        window,
14577                        cx,
14578                    );
14579                }
14580                if selections.len() == 1 {
14581                    let selection = selections
14582                        .last()
14583                        .expect("ensured that there's only one selection");
14584                    let query = buffer
14585                        .text_for_range(selection.start..selection.end)
14586                        .collect::<String>();
14587                    let is_empty = query.is_empty();
14588                    let select_state = SelectNextState {
14589                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14590                        wordwise: true,
14591                        done: is_empty,
14592                    };
14593                    self.select_prev_state = Some(select_state);
14594                } else {
14595                    self.select_prev_state = None;
14596                }
14597            } else if let Some(selected_text) = selected_text {
14598                self.select_prev_state = Some(SelectNextState {
14599                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14600                    wordwise: false,
14601                    done: false,
14602                });
14603                self.select_previous(action, window, cx)?;
14604            }
14605        }
14606        Ok(())
14607    }
14608
14609    pub fn find_next_match(
14610        &mut self,
14611        _: &FindNextMatch,
14612        window: &mut Window,
14613        cx: &mut Context<Self>,
14614    ) -> Result<()> {
14615        let selections = self.selections.disjoint_anchors_arc();
14616        match selections.first() {
14617            Some(first) if selections.len() >= 2 => {
14618                self.change_selections(Default::default(), window, cx, |s| {
14619                    s.select_ranges([first.range()]);
14620                });
14621            }
14622            _ => self.select_next(
14623                &SelectNext {
14624                    replace_newest: true,
14625                },
14626                window,
14627                cx,
14628            )?,
14629        }
14630        Ok(())
14631    }
14632
14633    pub fn find_previous_match(
14634        &mut self,
14635        _: &FindPreviousMatch,
14636        window: &mut Window,
14637        cx: &mut Context<Self>,
14638    ) -> Result<()> {
14639        let selections = self.selections.disjoint_anchors_arc();
14640        match selections.last() {
14641            Some(last) if selections.len() >= 2 => {
14642                self.change_selections(Default::default(), window, cx, |s| {
14643                    s.select_ranges([last.range()]);
14644                });
14645            }
14646            _ => self.select_previous(
14647                &SelectPrevious {
14648                    replace_newest: true,
14649                },
14650                window,
14651                cx,
14652            )?,
14653        }
14654        Ok(())
14655    }
14656
14657    pub fn toggle_comments(
14658        &mut self,
14659        action: &ToggleComments,
14660        window: &mut Window,
14661        cx: &mut Context<Self>,
14662    ) {
14663        if self.read_only(cx) {
14664            return;
14665        }
14666        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14667        let text_layout_details = &self.text_layout_details(window);
14668        self.transact(window, cx, |this, window, cx| {
14669            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14670            let mut edits = Vec::new();
14671            let mut selection_edit_ranges = Vec::new();
14672            let mut last_toggled_row = None;
14673            let snapshot = this.buffer.read(cx).read(cx);
14674            let empty_str: Arc<str> = Arc::default();
14675            let mut suffixes_inserted = Vec::new();
14676            let ignore_indent = action.ignore_indent;
14677
14678            fn comment_prefix_range(
14679                snapshot: &MultiBufferSnapshot,
14680                row: MultiBufferRow,
14681                comment_prefix: &str,
14682                comment_prefix_whitespace: &str,
14683                ignore_indent: bool,
14684            ) -> Range<Point> {
14685                let indent_size = if ignore_indent {
14686                    0
14687                } else {
14688                    snapshot.indent_size_for_line(row).len
14689                };
14690
14691                let start = Point::new(row.0, indent_size);
14692
14693                let mut line_bytes = snapshot
14694                    .bytes_in_range(start..snapshot.max_point())
14695                    .flatten()
14696                    .copied();
14697
14698                // If this line currently begins with the line comment prefix, then record
14699                // the range containing the prefix.
14700                if line_bytes
14701                    .by_ref()
14702                    .take(comment_prefix.len())
14703                    .eq(comment_prefix.bytes())
14704                {
14705                    // Include any whitespace that matches the comment prefix.
14706                    let matching_whitespace_len = line_bytes
14707                        .zip(comment_prefix_whitespace.bytes())
14708                        .take_while(|(a, b)| a == b)
14709                        .count() as u32;
14710                    let end = Point::new(
14711                        start.row,
14712                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14713                    );
14714                    start..end
14715                } else {
14716                    start..start
14717                }
14718            }
14719
14720            fn comment_suffix_range(
14721                snapshot: &MultiBufferSnapshot,
14722                row: MultiBufferRow,
14723                comment_suffix: &str,
14724                comment_suffix_has_leading_space: bool,
14725            ) -> Range<Point> {
14726                let end = Point::new(row.0, snapshot.line_len(row));
14727                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14728
14729                let mut line_end_bytes = snapshot
14730                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14731                    .flatten()
14732                    .copied();
14733
14734                let leading_space_len = if suffix_start_column > 0
14735                    && line_end_bytes.next() == Some(b' ')
14736                    && comment_suffix_has_leading_space
14737                {
14738                    1
14739                } else {
14740                    0
14741                };
14742
14743                // If this line currently begins with the line comment prefix, then record
14744                // the range containing the prefix.
14745                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14746                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14747                    start..end
14748                } else {
14749                    end..end
14750                }
14751            }
14752
14753            // TODO: Handle selections that cross excerpts
14754            for selection in &mut selections {
14755                let start_column = snapshot
14756                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14757                    .len;
14758                let language = if let Some(language) =
14759                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14760                {
14761                    language
14762                } else {
14763                    continue;
14764                };
14765
14766                selection_edit_ranges.clear();
14767
14768                // If multiple selections contain a given row, avoid processing that
14769                // row more than once.
14770                let mut start_row = MultiBufferRow(selection.start.row);
14771                if last_toggled_row == Some(start_row) {
14772                    start_row = start_row.next_row();
14773                }
14774                let end_row =
14775                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14776                        MultiBufferRow(selection.end.row - 1)
14777                    } else {
14778                        MultiBufferRow(selection.end.row)
14779                    };
14780                last_toggled_row = Some(end_row);
14781
14782                if start_row > end_row {
14783                    continue;
14784                }
14785
14786                // If the language has line comments, toggle those.
14787                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14788
14789                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14790                if ignore_indent {
14791                    full_comment_prefixes = full_comment_prefixes
14792                        .into_iter()
14793                        .map(|s| Arc::from(s.trim_end()))
14794                        .collect();
14795                }
14796
14797                if !full_comment_prefixes.is_empty() {
14798                    let first_prefix = full_comment_prefixes
14799                        .first()
14800                        .expect("prefixes is non-empty");
14801                    let prefix_trimmed_lengths = full_comment_prefixes
14802                        .iter()
14803                        .map(|p| p.trim_end_matches(' ').len())
14804                        .collect::<SmallVec<[usize; 4]>>();
14805
14806                    let mut all_selection_lines_are_comments = true;
14807
14808                    for row in start_row.0..=end_row.0 {
14809                        let row = MultiBufferRow(row);
14810                        if start_row < end_row && snapshot.is_line_blank(row) {
14811                            continue;
14812                        }
14813
14814                        let prefix_range = full_comment_prefixes
14815                            .iter()
14816                            .zip(prefix_trimmed_lengths.iter().copied())
14817                            .map(|(prefix, trimmed_prefix_len)| {
14818                                comment_prefix_range(
14819                                    snapshot.deref(),
14820                                    row,
14821                                    &prefix[..trimmed_prefix_len],
14822                                    &prefix[trimmed_prefix_len..],
14823                                    ignore_indent,
14824                                )
14825                            })
14826                            .max_by_key(|range| range.end.column - range.start.column)
14827                            .expect("prefixes is non-empty");
14828
14829                        if prefix_range.is_empty() {
14830                            all_selection_lines_are_comments = false;
14831                        }
14832
14833                        selection_edit_ranges.push(prefix_range);
14834                    }
14835
14836                    if all_selection_lines_are_comments {
14837                        edits.extend(
14838                            selection_edit_ranges
14839                                .iter()
14840                                .cloned()
14841                                .map(|range| (range, empty_str.clone())),
14842                        );
14843                    } else {
14844                        let min_column = selection_edit_ranges
14845                            .iter()
14846                            .map(|range| range.start.column)
14847                            .min()
14848                            .unwrap_or(0);
14849                        edits.extend(selection_edit_ranges.iter().map(|range| {
14850                            let position = Point::new(range.start.row, min_column);
14851                            (position..position, first_prefix.clone())
14852                        }));
14853                    }
14854                } else if let Some(BlockCommentConfig {
14855                    start: full_comment_prefix,
14856                    end: comment_suffix,
14857                    ..
14858                }) = language.block_comment()
14859                {
14860                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14861                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14862                    let prefix_range = comment_prefix_range(
14863                        snapshot.deref(),
14864                        start_row,
14865                        comment_prefix,
14866                        comment_prefix_whitespace,
14867                        ignore_indent,
14868                    );
14869                    let suffix_range = comment_suffix_range(
14870                        snapshot.deref(),
14871                        end_row,
14872                        comment_suffix.trim_start_matches(' '),
14873                        comment_suffix.starts_with(' '),
14874                    );
14875
14876                    if prefix_range.is_empty() || suffix_range.is_empty() {
14877                        edits.push((
14878                            prefix_range.start..prefix_range.start,
14879                            full_comment_prefix.clone(),
14880                        ));
14881                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14882                        suffixes_inserted.push((end_row, comment_suffix.len()));
14883                    } else {
14884                        edits.push((prefix_range, empty_str.clone()));
14885                        edits.push((suffix_range, empty_str.clone()));
14886                    }
14887                } else {
14888                    continue;
14889                }
14890            }
14891
14892            drop(snapshot);
14893            this.buffer.update(cx, |buffer, cx| {
14894                buffer.edit(edits, None, cx);
14895            });
14896
14897            // Adjust selections so that they end before any comment suffixes that
14898            // were inserted.
14899            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14900            let mut selections = this.selections.all::<Point>(cx);
14901            let snapshot = this.buffer.read(cx).read(cx);
14902            for selection in &mut selections {
14903                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14904                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14905                        Ordering::Less => {
14906                            suffixes_inserted.next();
14907                            continue;
14908                        }
14909                        Ordering::Greater => break,
14910                        Ordering::Equal => {
14911                            if selection.end.column == snapshot.line_len(row) {
14912                                if selection.is_empty() {
14913                                    selection.start.column -= suffix_len as u32;
14914                                }
14915                                selection.end.column -= suffix_len as u32;
14916                            }
14917                            break;
14918                        }
14919                    }
14920                }
14921            }
14922
14923            drop(snapshot);
14924            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14925
14926            let selections = this.selections.all::<Point>(cx);
14927            let selections_on_single_row = selections.windows(2).all(|selections| {
14928                selections[0].start.row == selections[1].start.row
14929                    && selections[0].end.row == selections[1].end.row
14930                    && selections[0].start.row == selections[0].end.row
14931            });
14932            let selections_selecting = selections
14933                .iter()
14934                .any(|selection| selection.start != selection.end);
14935            let advance_downwards = action.advance_downwards
14936                && selections_on_single_row
14937                && !selections_selecting
14938                && !matches!(this.mode, EditorMode::SingleLine);
14939
14940            if advance_downwards {
14941                let snapshot = this.buffer.read(cx).snapshot(cx);
14942
14943                this.change_selections(Default::default(), window, cx, |s| {
14944                    s.move_cursors_with(|display_snapshot, display_point, _| {
14945                        let mut point = display_point.to_point(display_snapshot);
14946                        point.row += 1;
14947                        point = snapshot.clip_point(point, Bias::Left);
14948                        let display_point = point.to_display_point(display_snapshot);
14949                        let goal = SelectionGoal::HorizontalPosition(
14950                            display_snapshot
14951                                .x_for_display_point(display_point, text_layout_details)
14952                                .into(),
14953                        );
14954                        (display_point, goal)
14955                    })
14956                });
14957            }
14958        });
14959    }
14960
14961    pub fn select_enclosing_symbol(
14962        &mut self,
14963        _: &SelectEnclosingSymbol,
14964        window: &mut Window,
14965        cx: &mut Context<Self>,
14966    ) {
14967        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14968
14969        let buffer = self.buffer.read(cx).snapshot(cx);
14970        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14971
14972        fn update_selection(
14973            selection: &Selection<usize>,
14974            buffer_snap: &MultiBufferSnapshot,
14975        ) -> Option<Selection<usize>> {
14976            let cursor = selection.head();
14977            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14978            for symbol in symbols.iter().rev() {
14979                let start = symbol.range.start.to_offset(buffer_snap);
14980                let end = symbol.range.end.to_offset(buffer_snap);
14981                let new_range = start..end;
14982                if start < selection.start || end > selection.end {
14983                    return Some(Selection {
14984                        id: selection.id,
14985                        start: new_range.start,
14986                        end: new_range.end,
14987                        goal: SelectionGoal::None,
14988                        reversed: selection.reversed,
14989                    });
14990                }
14991            }
14992            None
14993        }
14994
14995        let mut selected_larger_symbol = false;
14996        let new_selections = old_selections
14997            .iter()
14998            .map(|selection| match update_selection(selection, &buffer) {
14999                Some(new_selection) => {
15000                    if new_selection.range() != selection.range() {
15001                        selected_larger_symbol = true;
15002                    }
15003                    new_selection
15004                }
15005                None => selection.clone(),
15006            })
15007            .collect::<Vec<_>>();
15008
15009        if selected_larger_symbol {
15010            self.change_selections(Default::default(), window, cx, |s| {
15011                s.select(new_selections);
15012            });
15013        }
15014    }
15015
15016    pub fn select_larger_syntax_node(
15017        &mut self,
15018        _: &SelectLargerSyntaxNode,
15019        window: &mut Window,
15020        cx: &mut Context<Self>,
15021    ) {
15022        let Some(visible_row_count) = self.visible_row_count() else {
15023            return;
15024        };
15025        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15026        if old_selections.is_empty() {
15027            return;
15028        }
15029
15030        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15031
15032        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15033        let buffer = self.buffer.read(cx).snapshot(cx);
15034
15035        let mut selected_larger_node = false;
15036        let mut new_selections = old_selections
15037            .iter()
15038            .map(|selection| {
15039                let old_range = selection.start..selection.end;
15040
15041                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15042                    // manually select word at selection
15043                    if ["string_content", "inline"].contains(&node.kind()) {
15044                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15045                        // ignore if word is already selected
15046                        if !word_range.is_empty() && old_range != word_range {
15047                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15048                            // only select word if start and end point belongs to same word
15049                            if word_range == last_word_range {
15050                                selected_larger_node = true;
15051                                return Selection {
15052                                    id: selection.id,
15053                                    start: word_range.start,
15054                                    end: word_range.end,
15055                                    goal: SelectionGoal::None,
15056                                    reversed: selection.reversed,
15057                                };
15058                            }
15059                        }
15060                    }
15061                }
15062
15063                let mut new_range = old_range.clone();
15064                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
15065                {
15066                    new_range = match containing_range {
15067                        MultiOrSingleBufferOffsetRange::Single(_) => break,
15068                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15069                    };
15070                    if !node.is_named() {
15071                        continue;
15072                    }
15073                    if !display_map.intersects_fold(new_range.start)
15074                        && !display_map.intersects_fold(new_range.end)
15075                    {
15076                        break;
15077                    }
15078                }
15079
15080                selected_larger_node |= new_range != old_range;
15081                Selection {
15082                    id: selection.id,
15083                    start: new_range.start,
15084                    end: new_range.end,
15085                    goal: SelectionGoal::None,
15086                    reversed: selection.reversed,
15087                }
15088            })
15089            .collect::<Vec<_>>();
15090
15091        if !selected_larger_node {
15092            return; // don't put this call in the history
15093        }
15094
15095        // scroll based on transformation done to the last selection created by the user
15096        let (last_old, last_new) = old_selections
15097            .last()
15098            .zip(new_selections.last().cloned())
15099            .expect("old_selections isn't empty");
15100
15101        // revert selection
15102        let is_selection_reversed = {
15103            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15104            new_selections.last_mut().expect("checked above").reversed =
15105                should_newest_selection_be_reversed;
15106            should_newest_selection_be_reversed
15107        };
15108
15109        if selected_larger_node {
15110            self.select_syntax_node_history.disable_clearing = true;
15111            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15112                s.select(new_selections.clone());
15113            });
15114            self.select_syntax_node_history.disable_clearing = false;
15115        }
15116
15117        let start_row = last_new.start.to_display_point(&display_map).row().0;
15118        let end_row = last_new.end.to_display_point(&display_map).row().0;
15119        let selection_height = end_row - start_row + 1;
15120        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15121
15122        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15123        let scroll_behavior = if fits_on_the_screen {
15124            self.request_autoscroll(Autoscroll::fit(), cx);
15125            SelectSyntaxNodeScrollBehavior::FitSelection
15126        } else if is_selection_reversed {
15127            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15128            SelectSyntaxNodeScrollBehavior::CursorTop
15129        } else {
15130            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15131            SelectSyntaxNodeScrollBehavior::CursorBottom
15132        };
15133
15134        self.select_syntax_node_history.push((
15135            old_selections,
15136            scroll_behavior,
15137            is_selection_reversed,
15138        ));
15139    }
15140
15141    pub fn select_smaller_syntax_node(
15142        &mut self,
15143        _: &SelectSmallerSyntaxNode,
15144        window: &mut Window,
15145        cx: &mut Context<Self>,
15146    ) {
15147        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15148
15149        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15150            self.select_syntax_node_history.pop()
15151        {
15152            if let Some(selection) = selections.last_mut() {
15153                selection.reversed = is_selection_reversed;
15154            }
15155
15156            self.select_syntax_node_history.disable_clearing = true;
15157            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15158                s.select(selections.to_vec());
15159            });
15160            self.select_syntax_node_history.disable_clearing = false;
15161
15162            match scroll_behavior {
15163                SelectSyntaxNodeScrollBehavior::CursorTop => {
15164                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15165                }
15166                SelectSyntaxNodeScrollBehavior::FitSelection => {
15167                    self.request_autoscroll(Autoscroll::fit(), cx);
15168                }
15169                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15170                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15171                }
15172            }
15173        }
15174    }
15175
15176    pub fn unwrap_syntax_node(
15177        &mut self,
15178        _: &UnwrapSyntaxNode,
15179        window: &mut Window,
15180        cx: &mut Context<Self>,
15181    ) {
15182        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15183
15184        let buffer = self.buffer.read(cx).snapshot(cx);
15185        let selections = self
15186            .selections
15187            .all::<usize>(cx)
15188            .into_iter()
15189            // subtracting the offset requires sorting
15190            .sorted_by_key(|i| i.start);
15191
15192        let full_edits = selections
15193            .into_iter()
15194            .filter_map(|selection| {
15195                let child = if selection.is_empty()
15196                    && let Some((_, ancestor_range)) =
15197                        buffer.syntax_ancestor(selection.start..selection.end)
15198                {
15199                    match ancestor_range {
15200                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15201                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15202                    }
15203                } else {
15204                    selection.range()
15205                };
15206
15207                let mut parent = child.clone();
15208                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15209                    parent = match ancestor_range {
15210                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15211                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15212                    };
15213                    if parent.start < child.start || parent.end > child.end {
15214                        break;
15215                    }
15216                }
15217
15218                if parent == child {
15219                    return None;
15220                }
15221                let text = buffer.text_for_range(child).collect::<String>();
15222                Some((selection.id, parent, text))
15223            })
15224            .collect::<Vec<_>>();
15225        if full_edits.is_empty() {
15226            return;
15227        }
15228
15229        self.transact(window, cx, |this, window, cx| {
15230            this.buffer.update(cx, |buffer, cx| {
15231                buffer.edit(
15232                    full_edits
15233                        .iter()
15234                        .map(|(_, p, t)| (p.clone(), t.clone()))
15235                        .collect::<Vec<_>>(),
15236                    None,
15237                    cx,
15238                );
15239            });
15240            this.change_selections(Default::default(), window, cx, |s| {
15241                let mut offset = 0;
15242                let mut selections = vec![];
15243                for (id, parent, text) in full_edits {
15244                    let start = parent.start - offset;
15245                    offset += parent.len() - text.len();
15246                    selections.push(Selection {
15247                        id,
15248                        start,
15249                        end: start + text.len(),
15250                        reversed: false,
15251                        goal: Default::default(),
15252                    });
15253                }
15254                s.select(selections);
15255            });
15256        });
15257    }
15258
15259    pub fn select_next_syntax_node(
15260        &mut self,
15261        _: &SelectNextSyntaxNode,
15262        window: &mut Window,
15263        cx: &mut Context<Self>,
15264    ) {
15265        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15266        if old_selections.is_empty() {
15267            return;
15268        }
15269
15270        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15271
15272        let buffer = self.buffer.read(cx).snapshot(cx);
15273        let mut selected_sibling = false;
15274
15275        let new_selections = old_selections
15276            .iter()
15277            .map(|selection| {
15278                let old_range = selection.start..selection.end;
15279
15280                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15281                    let new_range = node.byte_range();
15282                    selected_sibling = true;
15283                    Selection {
15284                        id: selection.id,
15285                        start: new_range.start,
15286                        end: new_range.end,
15287                        goal: SelectionGoal::None,
15288                        reversed: selection.reversed,
15289                    }
15290                } else {
15291                    selection.clone()
15292                }
15293            })
15294            .collect::<Vec<_>>();
15295
15296        if selected_sibling {
15297            self.change_selections(
15298                SelectionEffects::scroll(Autoscroll::fit()),
15299                window,
15300                cx,
15301                |s| {
15302                    s.select(new_selections);
15303                },
15304            );
15305        }
15306    }
15307
15308    pub fn select_prev_syntax_node(
15309        &mut self,
15310        _: &SelectPreviousSyntaxNode,
15311        window: &mut Window,
15312        cx: &mut Context<Self>,
15313    ) {
15314        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15315        if old_selections.is_empty() {
15316            return;
15317        }
15318
15319        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15320
15321        let buffer = self.buffer.read(cx).snapshot(cx);
15322        let mut selected_sibling = false;
15323
15324        let new_selections = old_selections
15325            .iter()
15326            .map(|selection| {
15327                let old_range = selection.start..selection.end;
15328
15329                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15330                    let new_range = node.byte_range();
15331                    selected_sibling = true;
15332                    Selection {
15333                        id: selection.id,
15334                        start: new_range.start,
15335                        end: new_range.end,
15336                        goal: SelectionGoal::None,
15337                        reversed: selection.reversed,
15338                    }
15339                } else {
15340                    selection.clone()
15341                }
15342            })
15343            .collect::<Vec<_>>();
15344
15345        if selected_sibling {
15346            self.change_selections(
15347                SelectionEffects::scroll(Autoscroll::fit()),
15348                window,
15349                cx,
15350                |s| {
15351                    s.select(new_selections);
15352                },
15353            );
15354        }
15355    }
15356
15357    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15358        if !EditorSettings::get_global(cx).gutter.runnables {
15359            self.clear_tasks();
15360            return Task::ready(());
15361        }
15362        let project = self.project().map(Entity::downgrade);
15363        let task_sources = self.lsp_task_sources(cx);
15364        let multi_buffer = self.buffer.downgrade();
15365        cx.spawn_in(window, async move |editor, cx| {
15366            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15367            let Some(project) = project.and_then(|p| p.upgrade()) else {
15368                return;
15369            };
15370            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15371                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15372            }) else {
15373                return;
15374            };
15375
15376            let hide_runnables = project
15377                .update(cx, |project, _| project.is_via_collab())
15378                .unwrap_or(true);
15379            if hide_runnables {
15380                return;
15381            }
15382            let new_rows =
15383                cx.background_spawn({
15384                    let snapshot = display_snapshot.clone();
15385                    async move {
15386                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15387                    }
15388                })
15389                    .await;
15390            let Ok(lsp_tasks) =
15391                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15392            else {
15393                return;
15394            };
15395            let lsp_tasks = lsp_tasks.await;
15396
15397            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15398                lsp_tasks
15399                    .into_iter()
15400                    .flat_map(|(kind, tasks)| {
15401                        tasks.into_iter().filter_map(move |(location, task)| {
15402                            Some((kind.clone(), location?, task))
15403                        })
15404                    })
15405                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15406                        let buffer = location.target.buffer;
15407                        let buffer_snapshot = buffer.read(cx).snapshot();
15408                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15409                            |(excerpt_id, snapshot, _)| {
15410                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15411                                    display_snapshot
15412                                        .buffer_snapshot
15413                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15414                                } else {
15415                                    None
15416                                }
15417                            },
15418                        );
15419                        if let Some(offset) = offset {
15420                            let task_buffer_range =
15421                                location.target.range.to_point(&buffer_snapshot);
15422                            let context_buffer_range =
15423                                task_buffer_range.to_offset(&buffer_snapshot);
15424                            let context_range = BufferOffset(context_buffer_range.start)
15425                                ..BufferOffset(context_buffer_range.end);
15426
15427                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15428                                .or_insert_with(|| RunnableTasks {
15429                                    templates: Vec::new(),
15430                                    offset,
15431                                    column: task_buffer_range.start.column,
15432                                    extra_variables: HashMap::default(),
15433                                    context_range,
15434                                })
15435                                .templates
15436                                .push((kind, task.original_task().clone()));
15437                        }
15438
15439                        acc
15440                    })
15441            }) else {
15442                return;
15443            };
15444
15445            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15446                buffer.language_settings(cx).tasks.prefer_lsp
15447            }) else {
15448                return;
15449            };
15450
15451            let rows = Self::runnable_rows(
15452                project,
15453                display_snapshot,
15454                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15455                new_rows,
15456                cx.clone(),
15457            )
15458            .await;
15459            editor
15460                .update(cx, |editor, _| {
15461                    editor.clear_tasks();
15462                    for (key, mut value) in rows {
15463                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15464                            value.templates.extend(lsp_tasks.templates);
15465                        }
15466
15467                        editor.insert_tasks(key, value);
15468                    }
15469                    for (key, value) in lsp_tasks_by_rows {
15470                        editor.insert_tasks(key, value);
15471                    }
15472                })
15473                .ok();
15474        })
15475    }
15476    fn fetch_runnable_ranges(
15477        snapshot: &DisplaySnapshot,
15478        range: Range<Anchor>,
15479    ) -> Vec<language::RunnableRange> {
15480        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15481    }
15482
15483    fn runnable_rows(
15484        project: Entity<Project>,
15485        snapshot: DisplaySnapshot,
15486        prefer_lsp: bool,
15487        runnable_ranges: Vec<RunnableRange>,
15488        cx: AsyncWindowContext,
15489    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15490        cx.spawn(async move |cx| {
15491            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15492            for mut runnable in runnable_ranges {
15493                let Some(tasks) = cx
15494                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15495                    .ok()
15496                else {
15497                    continue;
15498                };
15499                let mut tasks = tasks.await;
15500
15501                if prefer_lsp {
15502                    tasks.retain(|(task_kind, _)| {
15503                        !matches!(task_kind, TaskSourceKind::Language { .. })
15504                    });
15505                }
15506                if tasks.is_empty() {
15507                    continue;
15508                }
15509
15510                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15511                let Some(row) = snapshot
15512                    .buffer_snapshot
15513                    .buffer_line_for_row(MultiBufferRow(point.row))
15514                    .map(|(_, range)| range.start.row)
15515                else {
15516                    continue;
15517                };
15518
15519                let context_range =
15520                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15521                runnable_rows.push((
15522                    (runnable.buffer_id, row),
15523                    RunnableTasks {
15524                        templates: tasks,
15525                        offset: snapshot
15526                            .buffer_snapshot
15527                            .anchor_before(runnable.run_range.start),
15528                        context_range,
15529                        column: point.column,
15530                        extra_variables: runnable.extra_captures,
15531                    },
15532                ));
15533            }
15534            runnable_rows
15535        })
15536    }
15537
15538    fn templates_with_tags(
15539        project: &Entity<Project>,
15540        runnable: &mut Runnable,
15541        cx: &mut App,
15542    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15543        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15544            let (worktree_id, file) = project
15545                .buffer_for_id(runnable.buffer, cx)
15546                .and_then(|buffer| buffer.read(cx).file())
15547                .map(|file| (file.worktree_id(cx), file.clone()))
15548                .unzip();
15549
15550            (
15551                project.task_store().read(cx).task_inventory().cloned(),
15552                worktree_id,
15553                file,
15554            )
15555        });
15556
15557        let tags = mem::take(&mut runnable.tags);
15558        let language = runnable.language.clone();
15559        cx.spawn(async move |cx| {
15560            let mut templates_with_tags = Vec::new();
15561            if let Some(inventory) = inventory {
15562                for RunnableTag(tag) in tags {
15563                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15564                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15565                    }) else {
15566                        return templates_with_tags;
15567                    };
15568                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15569                        move |(_, template)| {
15570                            template.tags.iter().any(|source_tag| source_tag == &tag)
15571                        },
15572                    ));
15573                }
15574            }
15575            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15576
15577            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15578                // Strongest source wins; if we have worktree tag binding, prefer that to
15579                // global and language bindings;
15580                // if we have a global binding, prefer that to language binding.
15581                let first_mismatch = templates_with_tags
15582                    .iter()
15583                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15584                if let Some(index) = first_mismatch {
15585                    templates_with_tags.truncate(index);
15586                }
15587            }
15588
15589            templates_with_tags
15590        })
15591    }
15592
15593    pub fn move_to_enclosing_bracket(
15594        &mut self,
15595        _: &MoveToEnclosingBracket,
15596        window: &mut Window,
15597        cx: &mut Context<Self>,
15598    ) {
15599        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15600        self.change_selections(Default::default(), window, cx, |s| {
15601            s.move_offsets_with(|snapshot, selection| {
15602                let Some(enclosing_bracket_ranges) =
15603                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15604                else {
15605                    return;
15606                };
15607
15608                let mut best_length = usize::MAX;
15609                let mut best_inside = false;
15610                let mut best_in_bracket_range = false;
15611                let mut best_destination = None;
15612                for (open, close) in enclosing_bracket_ranges {
15613                    let close = close.to_inclusive();
15614                    let length = close.end() - open.start;
15615                    let inside = selection.start >= open.end && selection.end <= *close.start();
15616                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15617                        || close.contains(&selection.head());
15618
15619                    // If best is next to a bracket and current isn't, skip
15620                    if !in_bracket_range && best_in_bracket_range {
15621                        continue;
15622                    }
15623
15624                    // Prefer smaller lengths unless best is inside and current isn't
15625                    if length > best_length && (best_inside || !inside) {
15626                        continue;
15627                    }
15628
15629                    best_length = length;
15630                    best_inside = inside;
15631                    best_in_bracket_range = in_bracket_range;
15632                    best_destination = Some(
15633                        if close.contains(&selection.start) && close.contains(&selection.end) {
15634                            if inside { open.end } else { open.start }
15635                        } else if inside {
15636                            *close.start()
15637                        } else {
15638                            *close.end()
15639                        },
15640                    );
15641                }
15642
15643                if let Some(destination) = best_destination {
15644                    selection.collapse_to(destination, SelectionGoal::None);
15645                }
15646            })
15647        });
15648    }
15649
15650    pub fn undo_selection(
15651        &mut self,
15652        _: &UndoSelection,
15653        window: &mut Window,
15654        cx: &mut Context<Self>,
15655    ) {
15656        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15657        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15658            self.selection_history.mode = SelectionHistoryMode::Undoing;
15659            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15660                this.end_selection(window, cx);
15661                this.change_selections(
15662                    SelectionEffects::scroll(Autoscroll::newest()),
15663                    window,
15664                    cx,
15665                    |s| s.select_anchors(entry.selections.to_vec()),
15666                );
15667            });
15668            self.selection_history.mode = SelectionHistoryMode::Normal;
15669
15670            self.select_next_state = entry.select_next_state;
15671            self.select_prev_state = entry.select_prev_state;
15672            self.add_selections_state = entry.add_selections_state;
15673        }
15674    }
15675
15676    pub fn redo_selection(
15677        &mut self,
15678        _: &RedoSelection,
15679        window: &mut Window,
15680        cx: &mut Context<Self>,
15681    ) {
15682        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15683        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15684            self.selection_history.mode = SelectionHistoryMode::Redoing;
15685            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15686                this.end_selection(window, cx);
15687                this.change_selections(
15688                    SelectionEffects::scroll(Autoscroll::newest()),
15689                    window,
15690                    cx,
15691                    |s| s.select_anchors(entry.selections.to_vec()),
15692                );
15693            });
15694            self.selection_history.mode = SelectionHistoryMode::Normal;
15695
15696            self.select_next_state = entry.select_next_state;
15697            self.select_prev_state = entry.select_prev_state;
15698            self.add_selections_state = entry.add_selections_state;
15699        }
15700    }
15701
15702    pub fn expand_excerpts(
15703        &mut self,
15704        action: &ExpandExcerpts,
15705        _: &mut Window,
15706        cx: &mut Context<Self>,
15707    ) {
15708        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15709    }
15710
15711    pub fn expand_excerpts_down(
15712        &mut self,
15713        action: &ExpandExcerptsDown,
15714        _: &mut Window,
15715        cx: &mut Context<Self>,
15716    ) {
15717        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15718    }
15719
15720    pub fn expand_excerpts_up(
15721        &mut self,
15722        action: &ExpandExcerptsUp,
15723        _: &mut Window,
15724        cx: &mut Context<Self>,
15725    ) {
15726        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15727    }
15728
15729    pub fn expand_excerpts_for_direction(
15730        &mut self,
15731        lines: u32,
15732        direction: ExpandExcerptDirection,
15733
15734        cx: &mut Context<Self>,
15735    ) {
15736        let selections = self.selections.disjoint_anchors_arc();
15737
15738        let lines = if lines == 0 {
15739            EditorSettings::get_global(cx).expand_excerpt_lines
15740        } else {
15741            lines
15742        };
15743
15744        self.buffer.update(cx, |buffer, cx| {
15745            let snapshot = buffer.snapshot(cx);
15746            let mut excerpt_ids = selections
15747                .iter()
15748                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15749                .collect::<Vec<_>>();
15750            excerpt_ids.sort();
15751            excerpt_ids.dedup();
15752            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15753        })
15754    }
15755
15756    pub fn expand_excerpt(
15757        &mut self,
15758        excerpt: ExcerptId,
15759        direction: ExpandExcerptDirection,
15760        window: &mut Window,
15761        cx: &mut Context<Self>,
15762    ) {
15763        let current_scroll_position = self.scroll_position(cx);
15764        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15765        let mut should_scroll_up = false;
15766
15767        if direction == ExpandExcerptDirection::Down {
15768            let multi_buffer = self.buffer.read(cx);
15769            let snapshot = multi_buffer.snapshot(cx);
15770            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15771                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15772                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15773            {
15774                let buffer_snapshot = buffer.read(cx).snapshot();
15775                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15776                let last_row = buffer_snapshot.max_point().row;
15777                let lines_below = last_row.saturating_sub(excerpt_end_row);
15778                should_scroll_up = lines_below >= lines_to_expand;
15779            }
15780        }
15781
15782        self.buffer.update(cx, |buffer, cx| {
15783            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15784        });
15785
15786        if should_scroll_up {
15787            let new_scroll_position =
15788                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15789            self.set_scroll_position(new_scroll_position, window, cx);
15790        }
15791    }
15792
15793    pub fn go_to_singleton_buffer_point(
15794        &mut self,
15795        point: Point,
15796        window: &mut Window,
15797        cx: &mut Context<Self>,
15798    ) {
15799        self.go_to_singleton_buffer_range(point..point, window, cx);
15800    }
15801
15802    pub fn go_to_singleton_buffer_range(
15803        &mut self,
15804        range: Range<Point>,
15805        window: &mut Window,
15806        cx: &mut Context<Self>,
15807    ) {
15808        let multibuffer = self.buffer().read(cx);
15809        let Some(buffer) = multibuffer.as_singleton() else {
15810            return;
15811        };
15812        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15813            return;
15814        };
15815        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15816            return;
15817        };
15818        self.change_selections(
15819            SelectionEffects::default().nav_history(true),
15820            window,
15821            cx,
15822            |s| s.select_anchor_ranges([start..end]),
15823        );
15824    }
15825
15826    pub fn go_to_diagnostic(
15827        &mut self,
15828        action: &GoToDiagnostic,
15829        window: &mut Window,
15830        cx: &mut Context<Self>,
15831    ) {
15832        if !self.diagnostics_enabled() {
15833            return;
15834        }
15835        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15836        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15837    }
15838
15839    pub fn go_to_prev_diagnostic(
15840        &mut self,
15841        action: &GoToPreviousDiagnostic,
15842        window: &mut Window,
15843        cx: &mut Context<Self>,
15844    ) {
15845        if !self.diagnostics_enabled() {
15846            return;
15847        }
15848        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15849        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15850    }
15851
15852    pub fn go_to_diagnostic_impl(
15853        &mut self,
15854        direction: Direction,
15855        severity: GoToDiagnosticSeverityFilter,
15856        window: &mut Window,
15857        cx: &mut Context<Self>,
15858    ) {
15859        let buffer = self.buffer.read(cx).snapshot(cx);
15860        let selection = self.selections.newest::<usize>(cx);
15861
15862        let mut active_group_id = None;
15863        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15864            && active_group.active_range.start.to_offset(&buffer) == selection.start
15865        {
15866            active_group_id = Some(active_group.group_id);
15867        }
15868
15869        fn filtered(
15870            snapshot: EditorSnapshot,
15871            severity: GoToDiagnosticSeverityFilter,
15872            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15873        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15874            diagnostics
15875                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15876                .filter(|entry| entry.range.start != entry.range.end)
15877                .filter(|entry| !entry.diagnostic.is_unnecessary)
15878                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15879        }
15880
15881        let snapshot = self.snapshot(window, cx);
15882        let before = filtered(
15883            snapshot.clone(),
15884            severity,
15885            buffer
15886                .diagnostics_in_range(0..selection.start)
15887                .filter(|entry| entry.range.start <= selection.start),
15888        );
15889        let after = filtered(
15890            snapshot,
15891            severity,
15892            buffer
15893                .diagnostics_in_range(selection.start..buffer.len())
15894                .filter(|entry| entry.range.start >= selection.start),
15895        );
15896
15897        let mut found: Option<DiagnosticEntry<usize>> = None;
15898        if direction == Direction::Prev {
15899            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15900            {
15901                for diagnostic in prev_diagnostics.into_iter().rev() {
15902                    if diagnostic.range.start != selection.start
15903                        || active_group_id
15904                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15905                    {
15906                        found = Some(diagnostic);
15907                        break 'outer;
15908                    }
15909                }
15910            }
15911        } else {
15912            for diagnostic in after.chain(before) {
15913                if diagnostic.range.start != selection.start
15914                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15915                {
15916                    found = Some(diagnostic);
15917                    break;
15918                }
15919            }
15920        }
15921        let Some(next_diagnostic) = found else {
15922            return;
15923        };
15924
15925        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15926        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15927            return;
15928        };
15929        self.change_selections(Default::default(), window, cx, |s| {
15930            s.select_ranges(vec![
15931                next_diagnostic.range.start..next_diagnostic.range.start,
15932            ])
15933        });
15934        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15935        self.refresh_edit_prediction(false, true, window, cx);
15936    }
15937
15938    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15939        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15940        let snapshot = self.snapshot(window, cx);
15941        let selection = self.selections.newest::<Point>(cx);
15942        self.go_to_hunk_before_or_after_position(
15943            &snapshot,
15944            selection.head(),
15945            Direction::Next,
15946            window,
15947            cx,
15948        );
15949    }
15950
15951    pub fn go_to_hunk_before_or_after_position(
15952        &mut self,
15953        snapshot: &EditorSnapshot,
15954        position: Point,
15955        direction: Direction,
15956        window: &mut Window,
15957        cx: &mut Context<Editor>,
15958    ) {
15959        let row = if direction == Direction::Next {
15960            self.hunk_after_position(snapshot, position)
15961                .map(|hunk| hunk.row_range.start)
15962        } else {
15963            self.hunk_before_position(snapshot, position)
15964        };
15965
15966        if let Some(row) = row {
15967            let destination = Point::new(row.0, 0);
15968            let autoscroll = Autoscroll::center();
15969
15970            self.unfold_ranges(&[destination..destination], false, false, cx);
15971            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15972                s.select_ranges([destination..destination]);
15973            });
15974        }
15975    }
15976
15977    fn hunk_after_position(
15978        &mut self,
15979        snapshot: &EditorSnapshot,
15980        position: Point,
15981    ) -> Option<MultiBufferDiffHunk> {
15982        snapshot
15983            .buffer_snapshot
15984            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15985            .find(|hunk| hunk.row_range.start.0 > position.row)
15986            .or_else(|| {
15987                snapshot
15988                    .buffer_snapshot
15989                    .diff_hunks_in_range(Point::zero()..position)
15990                    .find(|hunk| hunk.row_range.end.0 < position.row)
15991            })
15992    }
15993
15994    fn go_to_prev_hunk(
15995        &mut self,
15996        _: &GoToPreviousHunk,
15997        window: &mut Window,
15998        cx: &mut Context<Self>,
15999    ) {
16000        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16001        let snapshot = self.snapshot(window, cx);
16002        let selection = self.selections.newest::<Point>(cx);
16003        self.go_to_hunk_before_or_after_position(
16004            &snapshot,
16005            selection.head(),
16006            Direction::Prev,
16007            window,
16008            cx,
16009        );
16010    }
16011
16012    fn hunk_before_position(
16013        &mut self,
16014        snapshot: &EditorSnapshot,
16015        position: Point,
16016    ) -> Option<MultiBufferRow> {
16017        snapshot
16018            .buffer_snapshot
16019            .diff_hunk_before(position)
16020            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
16021    }
16022
16023    fn go_to_next_change(
16024        &mut self,
16025        _: &GoToNextChange,
16026        window: &mut Window,
16027        cx: &mut Context<Self>,
16028    ) {
16029        if let Some(selections) = self
16030            .change_list
16031            .next_change(1, Direction::Next)
16032            .map(|s| s.to_vec())
16033        {
16034            self.change_selections(Default::default(), window, cx, |s| {
16035                let map = s.display_map();
16036                s.select_display_ranges(selections.iter().map(|a| {
16037                    let point = a.to_display_point(&map);
16038                    point..point
16039                }))
16040            })
16041        }
16042    }
16043
16044    fn go_to_previous_change(
16045        &mut self,
16046        _: &GoToPreviousChange,
16047        window: &mut Window,
16048        cx: &mut Context<Self>,
16049    ) {
16050        if let Some(selections) = self
16051            .change_list
16052            .next_change(1, Direction::Prev)
16053            .map(|s| s.to_vec())
16054        {
16055            self.change_selections(Default::default(), window, cx, |s| {
16056                let map = s.display_map();
16057                s.select_display_ranges(selections.iter().map(|a| {
16058                    let point = a.to_display_point(&map);
16059                    point..point
16060                }))
16061            })
16062        }
16063    }
16064
16065    pub fn go_to_next_document_highlight(
16066        &mut self,
16067        _: &GoToNextDocumentHighlight,
16068        window: &mut Window,
16069        cx: &mut Context<Self>,
16070    ) {
16071        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16072    }
16073
16074    pub fn go_to_prev_document_highlight(
16075        &mut self,
16076        _: &GoToPreviousDocumentHighlight,
16077        window: &mut Window,
16078        cx: &mut Context<Self>,
16079    ) {
16080        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16081    }
16082
16083    pub fn go_to_document_highlight_before_or_after_position(
16084        &mut self,
16085        direction: Direction,
16086        window: &mut Window,
16087        cx: &mut Context<Editor>,
16088    ) {
16089        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16090        let snapshot = self.snapshot(window, cx);
16091        let buffer = &snapshot.buffer_snapshot;
16092        let position = self.selections.newest::<Point>(cx).head();
16093        let anchor_position = buffer.anchor_after(position);
16094
16095        // Get all document highlights (both read and write)
16096        let mut all_highlights = Vec::new();
16097
16098        if let Some((_, read_highlights)) = self
16099            .background_highlights
16100            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16101        {
16102            all_highlights.extend(read_highlights.iter());
16103        }
16104
16105        if let Some((_, write_highlights)) = self
16106            .background_highlights
16107            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16108        {
16109            all_highlights.extend(write_highlights.iter());
16110        }
16111
16112        if all_highlights.is_empty() {
16113            return;
16114        }
16115
16116        // Sort highlights by position
16117        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16118
16119        let target_highlight = match direction {
16120            Direction::Next => {
16121                // Find the first highlight after the current position
16122                all_highlights
16123                    .iter()
16124                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16125            }
16126            Direction::Prev => {
16127                // Find the last highlight before the current position
16128                all_highlights
16129                    .iter()
16130                    .rev()
16131                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16132            }
16133        };
16134
16135        if let Some(highlight) = target_highlight {
16136            let destination = highlight.start.to_point(buffer);
16137            let autoscroll = Autoscroll::center();
16138
16139            self.unfold_ranges(&[destination..destination], false, false, cx);
16140            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16141                s.select_ranges([destination..destination]);
16142            });
16143        }
16144    }
16145
16146    fn go_to_line<T: 'static>(
16147        &mut self,
16148        position: Anchor,
16149        highlight_color: Option<Hsla>,
16150        window: &mut Window,
16151        cx: &mut Context<Self>,
16152    ) {
16153        let snapshot = self.snapshot(window, cx).display_snapshot;
16154        let position = position.to_point(&snapshot.buffer_snapshot);
16155        let start = snapshot
16156            .buffer_snapshot
16157            .clip_point(Point::new(position.row, 0), Bias::Left);
16158        let end = start + Point::new(1, 0);
16159        let start = snapshot.buffer_snapshot.anchor_before(start);
16160        let end = snapshot.buffer_snapshot.anchor_before(end);
16161
16162        self.highlight_rows::<T>(
16163            start..end,
16164            highlight_color
16165                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16166            Default::default(),
16167            cx,
16168        );
16169
16170        if self.buffer.read(cx).is_singleton() {
16171            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16172        }
16173    }
16174
16175    pub fn go_to_definition(
16176        &mut self,
16177        _: &GoToDefinition,
16178        window: &mut Window,
16179        cx: &mut Context<Self>,
16180    ) -> Task<Result<Navigated>> {
16181        let definition =
16182            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16183        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16184        cx.spawn_in(window, async move |editor, cx| {
16185            if definition.await? == Navigated::Yes {
16186                return Ok(Navigated::Yes);
16187            }
16188            match fallback_strategy {
16189                GoToDefinitionFallback::None => Ok(Navigated::No),
16190                GoToDefinitionFallback::FindAllReferences => {
16191                    match editor.update_in(cx, |editor, window, cx| {
16192                        editor.find_all_references(&FindAllReferences, window, cx)
16193                    })? {
16194                        Some(references) => references.await,
16195                        None => Ok(Navigated::No),
16196                    }
16197                }
16198            }
16199        })
16200    }
16201
16202    pub fn go_to_declaration(
16203        &mut self,
16204        _: &GoToDeclaration,
16205        window: &mut Window,
16206        cx: &mut Context<Self>,
16207    ) -> Task<Result<Navigated>> {
16208        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16209    }
16210
16211    pub fn go_to_declaration_split(
16212        &mut self,
16213        _: &GoToDeclaration,
16214        window: &mut Window,
16215        cx: &mut Context<Self>,
16216    ) -> Task<Result<Navigated>> {
16217        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16218    }
16219
16220    pub fn go_to_implementation(
16221        &mut self,
16222        _: &GoToImplementation,
16223        window: &mut Window,
16224        cx: &mut Context<Self>,
16225    ) -> Task<Result<Navigated>> {
16226        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16227    }
16228
16229    pub fn go_to_implementation_split(
16230        &mut self,
16231        _: &GoToImplementationSplit,
16232        window: &mut Window,
16233        cx: &mut Context<Self>,
16234    ) -> Task<Result<Navigated>> {
16235        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16236    }
16237
16238    pub fn go_to_type_definition(
16239        &mut self,
16240        _: &GoToTypeDefinition,
16241        window: &mut Window,
16242        cx: &mut Context<Self>,
16243    ) -> Task<Result<Navigated>> {
16244        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16245    }
16246
16247    pub fn go_to_definition_split(
16248        &mut self,
16249        _: &GoToDefinitionSplit,
16250        window: &mut Window,
16251        cx: &mut Context<Self>,
16252    ) -> Task<Result<Navigated>> {
16253        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16254    }
16255
16256    pub fn go_to_type_definition_split(
16257        &mut self,
16258        _: &GoToTypeDefinitionSplit,
16259        window: &mut Window,
16260        cx: &mut Context<Self>,
16261    ) -> Task<Result<Navigated>> {
16262        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16263    }
16264
16265    fn go_to_definition_of_kind(
16266        &mut self,
16267        kind: GotoDefinitionKind,
16268        split: bool,
16269        window: &mut Window,
16270        cx: &mut Context<Self>,
16271    ) -> Task<Result<Navigated>> {
16272        let Some(provider) = self.semantics_provider.clone() else {
16273            return Task::ready(Ok(Navigated::No));
16274        };
16275        let head = self.selections.newest::<usize>(cx).head();
16276        let buffer = self.buffer.read(cx);
16277        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16278            return Task::ready(Ok(Navigated::No));
16279        };
16280        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16281            return Task::ready(Ok(Navigated::No));
16282        };
16283
16284        cx.spawn_in(window, async move |editor, cx| {
16285            let Some(definitions) = definitions.await? else {
16286                return Ok(Navigated::No);
16287            };
16288            let navigated = editor
16289                .update_in(cx, |editor, window, cx| {
16290                    editor.navigate_to_hover_links(
16291                        Some(kind),
16292                        definitions
16293                            .into_iter()
16294                            .filter(|location| {
16295                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16296                            })
16297                            .map(HoverLink::Text)
16298                            .collect::<Vec<_>>(),
16299                        split,
16300                        window,
16301                        cx,
16302                    )
16303                })?
16304                .await?;
16305            anyhow::Ok(navigated)
16306        })
16307    }
16308
16309    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16310        let selection = self.selections.newest_anchor();
16311        let head = selection.head();
16312        let tail = selection.tail();
16313
16314        let Some((buffer, start_position)) =
16315            self.buffer.read(cx).text_anchor_for_position(head, cx)
16316        else {
16317            return;
16318        };
16319
16320        let end_position = if head != tail {
16321            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16322                return;
16323            };
16324            Some(pos)
16325        } else {
16326            None
16327        };
16328
16329        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16330            let url = if let Some(end_pos) = end_position {
16331                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16332            } else {
16333                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16334            };
16335
16336            if let Some(url) = url {
16337                cx.update(|window, cx| {
16338                    if parse_zed_link(&url, cx).is_some() {
16339                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16340                    } else {
16341                        cx.open_url(&url);
16342                    }
16343                })?;
16344            }
16345
16346            anyhow::Ok(())
16347        });
16348
16349        url_finder.detach();
16350    }
16351
16352    pub fn open_selected_filename(
16353        &mut self,
16354        _: &OpenSelectedFilename,
16355        window: &mut Window,
16356        cx: &mut Context<Self>,
16357    ) {
16358        let Some(workspace) = self.workspace() else {
16359            return;
16360        };
16361
16362        let position = self.selections.newest_anchor().head();
16363
16364        let Some((buffer, buffer_position)) =
16365            self.buffer.read(cx).text_anchor_for_position(position, cx)
16366        else {
16367            return;
16368        };
16369
16370        let project = self.project.clone();
16371
16372        cx.spawn_in(window, async move |_, cx| {
16373            let result = find_file(&buffer, project, buffer_position, cx).await;
16374
16375            if let Some((_, path)) = result {
16376                workspace
16377                    .update_in(cx, |workspace, window, cx| {
16378                        workspace.open_resolved_path(path, window, cx)
16379                    })?
16380                    .await?;
16381            }
16382            anyhow::Ok(())
16383        })
16384        .detach();
16385    }
16386
16387    pub(crate) fn navigate_to_hover_links(
16388        &mut self,
16389        kind: Option<GotoDefinitionKind>,
16390        definitions: Vec<HoverLink>,
16391        split: bool,
16392        window: &mut Window,
16393        cx: &mut Context<Editor>,
16394    ) -> Task<Result<Navigated>> {
16395        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16396        let mut first_url_or_file = None;
16397        let definitions: Vec<_> = definitions
16398            .into_iter()
16399            .filter_map(|def| match def {
16400                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16401                HoverLink::InlayHint(lsp_location, server_id) => {
16402                    let computation =
16403                        self.compute_target_location(lsp_location, server_id, window, cx);
16404                    Some(cx.background_spawn(computation))
16405                }
16406                HoverLink::Url(url) => {
16407                    first_url_or_file = Some(Either::Left(url));
16408                    None
16409                }
16410                HoverLink::File(path) => {
16411                    first_url_or_file = Some(Either::Right(path));
16412                    None
16413                }
16414            })
16415            .collect();
16416
16417        let workspace = self.workspace();
16418
16419        cx.spawn_in(window, async move |editor, cx| {
16420            let locations: Vec<Location> = future::join_all(definitions)
16421                .await
16422                .into_iter()
16423                .filter_map(|location| location.transpose())
16424                .collect::<Result<_>>()
16425                .context("location tasks")?;
16426            let mut locations = cx.update(|_, cx| {
16427                locations
16428                    .into_iter()
16429                    .map(|location| {
16430                        let buffer = location.buffer.read(cx);
16431                        (location.buffer, location.range.to_point(buffer))
16432                    })
16433                    .into_group_map()
16434            })?;
16435            let mut num_locations = 0;
16436            for ranges in locations.values_mut() {
16437                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16438                ranges.dedup();
16439                num_locations += ranges.len();
16440            }
16441
16442            if num_locations > 1 {
16443                let Some(workspace) = workspace else {
16444                    return Ok(Navigated::No);
16445                };
16446
16447                let tab_kind = match kind {
16448                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16449                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16450                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16451                    Some(GotoDefinitionKind::Type) => "Types",
16452                };
16453                let title = editor
16454                    .update_in(cx, |_, _, cx| {
16455                        let target = locations
16456                            .iter()
16457                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16458                            .map(|(buffer, location)| {
16459                                buffer
16460                                    .read(cx)
16461                                    .text_for_range(location.clone())
16462                                    .collect::<String>()
16463                            })
16464                            .filter(|text| !text.contains('\n'))
16465                            .unique()
16466                            .take(3)
16467                            .join(", ");
16468                        if target.is_empty() {
16469                            tab_kind.to_owned()
16470                        } else {
16471                            format!("{tab_kind} for {target}")
16472                        }
16473                    })
16474                    .context("buffer title")?;
16475
16476                let opened = workspace
16477                    .update_in(cx, |workspace, window, cx| {
16478                        Self::open_locations_in_multibuffer(
16479                            workspace,
16480                            locations,
16481                            title,
16482                            split,
16483                            MultibufferSelectionMode::First,
16484                            window,
16485                            cx,
16486                        )
16487                    })
16488                    .is_ok();
16489
16490                anyhow::Ok(Navigated::from_bool(opened))
16491            } else if num_locations == 0 {
16492                // If there is one url or file, open it directly
16493                match first_url_or_file {
16494                    Some(Either::Left(url)) => {
16495                        cx.update(|_, cx| cx.open_url(&url))?;
16496                        Ok(Navigated::Yes)
16497                    }
16498                    Some(Either::Right(path)) => {
16499                        let Some(workspace) = workspace else {
16500                            return Ok(Navigated::No);
16501                        };
16502
16503                        workspace
16504                            .update_in(cx, |workspace, window, cx| {
16505                                workspace.open_resolved_path(path, window, cx)
16506                            })?
16507                            .await?;
16508                        Ok(Navigated::Yes)
16509                    }
16510                    None => Ok(Navigated::No),
16511                }
16512            } else {
16513                let Some(workspace) = workspace else {
16514                    return Ok(Navigated::No);
16515                };
16516
16517                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16518                let target_range = target_ranges.first().unwrap().clone();
16519
16520                editor.update_in(cx, |editor, window, cx| {
16521                    let range = target_range.to_point(target_buffer.read(cx));
16522                    let range = editor.range_for_match(&range);
16523                    let range = collapse_multiline_range(range);
16524
16525                    if !split
16526                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16527                    {
16528                        editor.go_to_singleton_buffer_range(range, window, cx);
16529                    } else {
16530                        let pane = workspace.read(cx).active_pane().clone();
16531                        window.defer(cx, move |window, cx| {
16532                            let target_editor: Entity<Self> =
16533                                workspace.update(cx, |workspace, cx| {
16534                                    let pane = if split {
16535                                        workspace.adjacent_pane(window, cx)
16536                                    } else {
16537                                        workspace.active_pane().clone()
16538                                    };
16539
16540                                    workspace.open_project_item(
16541                                        pane,
16542                                        target_buffer.clone(),
16543                                        true,
16544                                        true,
16545                                        window,
16546                                        cx,
16547                                    )
16548                                });
16549                            target_editor.update(cx, |target_editor, cx| {
16550                                // When selecting a definition in a different buffer, disable the nav history
16551                                // to avoid creating a history entry at the previous cursor location.
16552                                pane.update(cx, |pane, _| pane.disable_history());
16553                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16554                                pane.update(cx, |pane, _| pane.enable_history());
16555                            });
16556                        });
16557                    }
16558                    Navigated::Yes
16559                })
16560            }
16561        })
16562    }
16563
16564    fn compute_target_location(
16565        &self,
16566        lsp_location: lsp::Location,
16567        server_id: LanguageServerId,
16568        window: &mut Window,
16569        cx: &mut Context<Self>,
16570    ) -> Task<anyhow::Result<Option<Location>>> {
16571        let Some(project) = self.project.clone() else {
16572            return Task::ready(Ok(None));
16573        };
16574
16575        cx.spawn_in(window, async move |editor, cx| {
16576            let location_task = editor.update(cx, |_, cx| {
16577                project.update(cx, |project, cx| {
16578                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16579                })
16580            })?;
16581            let location = Some({
16582                let target_buffer_handle = location_task.await.context("open local buffer")?;
16583                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16584                    let target_start = target_buffer
16585                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16586                    let target_end = target_buffer
16587                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16588                    target_buffer.anchor_after(target_start)
16589                        ..target_buffer.anchor_before(target_end)
16590                })?;
16591                Location {
16592                    buffer: target_buffer_handle,
16593                    range,
16594                }
16595            });
16596            Ok(location)
16597        })
16598    }
16599
16600    pub fn find_all_references(
16601        &mut self,
16602        _: &FindAllReferences,
16603        window: &mut Window,
16604        cx: &mut Context<Self>,
16605    ) -> Option<Task<Result<Navigated>>> {
16606        let selection = self.selections.newest::<usize>(cx);
16607        let multi_buffer = self.buffer.read(cx);
16608        let head = selection.head();
16609
16610        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16611        let head_anchor = multi_buffer_snapshot.anchor_at(
16612            head,
16613            if head < selection.tail() {
16614                Bias::Right
16615            } else {
16616                Bias::Left
16617            },
16618        );
16619
16620        match self
16621            .find_all_references_task_sources
16622            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16623        {
16624            Ok(_) => {
16625                log::info!(
16626                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16627                );
16628                return None;
16629            }
16630            Err(i) => {
16631                self.find_all_references_task_sources.insert(i, head_anchor);
16632            }
16633        }
16634
16635        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16636        let workspace = self.workspace()?;
16637        let project = workspace.read(cx).project().clone();
16638        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16639        Some(cx.spawn_in(window, async move |editor, cx| {
16640            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16641                if let Ok(i) = editor
16642                    .find_all_references_task_sources
16643                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16644                {
16645                    editor.find_all_references_task_sources.remove(i);
16646                }
16647            });
16648
16649            let Some(locations) = references.await? else {
16650                return anyhow::Ok(Navigated::No);
16651            };
16652            let mut locations = cx.update(|_, cx| {
16653                locations
16654                    .into_iter()
16655                    .map(|location| {
16656                        let buffer = location.buffer.read(cx);
16657                        (location.buffer, location.range.to_point(buffer))
16658                    })
16659                    .into_group_map()
16660            })?;
16661            if locations.is_empty() {
16662                return anyhow::Ok(Navigated::No);
16663            }
16664            for ranges in locations.values_mut() {
16665                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16666                ranges.dedup();
16667            }
16668
16669            workspace.update_in(cx, |workspace, window, cx| {
16670                let target = locations
16671                    .iter()
16672                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16673                    .map(|(buffer, location)| {
16674                        buffer
16675                            .read(cx)
16676                            .text_for_range(location.clone())
16677                            .collect::<String>()
16678                    })
16679                    .filter(|text| !text.contains('\n'))
16680                    .unique()
16681                    .take(3)
16682                    .join(", ");
16683                let title = if target.is_empty() {
16684                    "References".to_owned()
16685                } else {
16686                    format!("References to {target}")
16687                };
16688                Self::open_locations_in_multibuffer(
16689                    workspace,
16690                    locations,
16691                    title,
16692                    false,
16693                    MultibufferSelectionMode::First,
16694                    window,
16695                    cx,
16696                );
16697                Navigated::Yes
16698            })
16699        }))
16700    }
16701
16702    /// Opens a multibuffer with the given project locations in it
16703    pub fn open_locations_in_multibuffer(
16704        workspace: &mut Workspace,
16705        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16706        title: String,
16707        split: bool,
16708        multibuffer_selection_mode: MultibufferSelectionMode,
16709        window: &mut Window,
16710        cx: &mut Context<Workspace>,
16711    ) {
16712        if locations.is_empty() {
16713            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16714            return;
16715        }
16716
16717        let capability = workspace.project().read(cx).capability();
16718        let mut ranges = <Vec<Range<Anchor>>>::new();
16719
16720        // a key to find existing multibuffer editors with the same set of locations
16721        // to prevent us from opening more and more multibuffer tabs for searches and the like
16722        let mut key = (title.clone(), vec![]);
16723        let excerpt_buffer = cx.new(|cx| {
16724            let key = &mut key.1;
16725            let mut multibuffer = MultiBuffer::new(capability);
16726            for (buffer, mut ranges_for_buffer) in locations {
16727                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16728                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16729                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16730                    PathKey::for_buffer(&buffer, cx),
16731                    buffer.clone(),
16732                    ranges_for_buffer,
16733                    multibuffer_context_lines(cx),
16734                    cx,
16735                );
16736                ranges.extend(new_ranges)
16737            }
16738
16739            multibuffer.with_title(title)
16740        });
16741        let existing = workspace.active_pane().update(cx, |pane, cx| {
16742            pane.items()
16743                .filter_map(|item| item.downcast::<Editor>())
16744                .find(|editor| {
16745                    editor
16746                        .read(cx)
16747                        .lookup_key
16748                        .as_ref()
16749                        .and_then(|it| {
16750                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16751                        })
16752                        .is_some_and(|it| *it == key)
16753                })
16754        });
16755        let editor = existing.unwrap_or_else(|| {
16756            cx.new(|cx| {
16757                let mut editor = Editor::for_multibuffer(
16758                    excerpt_buffer,
16759                    Some(workspace.project().clone()),
16760                    window,
16761                    cx,
16762                );
16763                editor.lookup_key = Some(Box::new(key));
16764                editor
16765            })
16766        });
16767        editor.update(cx, |editor, cx| {
16768            match multibuffer_selection_mode {
16769                MultibufferSelectionMode::First => {
16770                    if let Some(first_range) = ranges.first() {
16771                        editor.change_selections(
16772                            SelectionEffects::no_scroll(),
16773                            window,
16774                            cx,
16775                            |selections| {
16776                                selections.clear_disjoint();
16777                                selections
16778                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16779                            },
16780                        );
16781                    }
16782                    editor.highlight_background::<Self>(
16783                        &ranges,
16784                        |theme| theme.colors().editor_highlighted_line_background,
16785                        cx,
16786                    );
16787                }
16788                MultibufferSelectionMode::All => {
16789                    editor.change_selections(
16790                        SelectionEffects::no_scroll(),
16791                        window,
16792                        cx,
16793                        |selections| {
16794                            selections.clear_disjoint();
16795                            selections.select_anchor_ranges(ranges);
16796                        },
16797                    );
16798                }
16799            }
16800            editor.register_buffers_with_language_servers(cx);
16801        });
16802
16803        let item = Box::new(editor);
16804        let item_id = item.item_id();
16805
16806        if split {
16807            workspace.split_item(SplitDirection::Right, item, window, cx);
16808        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16809            let (preview_item_id, preview_item_idx) =
16810                workspace.active_pane().read_with(cx, |pane, _| {
16811                    (pane.preview_item_id(), pane.preview_item_idx())
16812                });
16813
16814            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16815
16816            if let Some(preview_item_id) = preview_item_id {
16817                workspace.active_pane().update(cx, |pane, cx| {
16818                    pane.remove_item(preview_item_id, false, false, window, cx);
16819                });
16820            }
16821        } else {
16822            workspace.add_item_to_active_pane(item, None, true, window, cx);
16823        }
16824        workspace.active_pane().update(cx, |pane, cx| {
16825            pane.set_preview_item_id(Some(item_id), cx);
16826        });
16827    }
16828
16829    pub fn rename(
16830        &mut self,
16831        _: &Rename,
16832        window: &mut Window,
16833        cx: &mut Context<Self>,
16834    ) -> Option<Task<Result<()>>> {
16835        use language::ToOffset as _;
16836
16837        let provider = self.semantics_provider.clone()?;
16838        let selection = self.selections.newest_anchor().clone();
16839        let (cursor_buffer, cursor_buffer_position) = self
16840            .buffer
16841            .read(cx)
16842            .text_anchor_for_position(selection.head(), cx)?;
16843        let (tail_buffer, cursor_buffer_position_end) = self
16844            .buffer
16845            .read(cx)
16846            .text_anchor_for_position(selection.tail(), cx)?;
16847        if tail_buffer != cursor_buffer {
16848            return None;
16849        }
16850
16851        let snapshot = cursor_buffer.read(cx).snapshot();
16852        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16853        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16854        let prepare_rename = provider
16855            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16856            .unwrap_or_else(|| Task::ready(Ok(None)));
16857        drop(snapshot);
16858
16859        Some(cx.spawn_in(window, async move |this, cx| {
16860            let rename_range = if let Some(range) = prepare_rename.await? {
16861                Some(range)
16862            } else {
16863                this.update(cx, |this, cx| {
16864                    let buffer = this.buffer.read(cx).snapshot(cx);
16865                    let mut buffer_highlights = this
16866                        .document_highlights_for_position(selection.head(), &buffer)
16867                        .filter(|highlight| {
16868                            highlight.start.excerpt_id == selection.head().excerpt_id
16869                                && highlight.end.excerpt_id == selection.head().excerpt_id
16870                        });
16871                    buffer_highlights
16872                        .next()
16873                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16874                })?
16875            };
16876            if let Some(rename_range) = rename_range {
16877                this.update_in(cx, |this, window, cx| {
16878                    let snapshot = cursor_buffer.read(cx).snapshot();
16879                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16880                    let cursor_offset_in_rename_range =
16881                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16882                    let cursor_offset_in_rename_range_end =
16883                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16884
16885                    this.take_rename(false, window, cx);
16886                    let buffer = this.buffer.read(cx).read(cx);
16887                    let cursor_offset = selection.head().to_offset(&buffer);
16888                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16889                    let rename_end = rename_start + rename_buffer_range.len();
16890                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16891                    let mut old_highlight_id = None;
16892                    let old_name: Arc<str> = buffer
16893                        .chunks(rename_start..rename_end, true)
16894                        .map(|chunk| {
16895                            if old_highlight_id.is_none() {
16896                                old_highlight_id = chunk.syntax_highlight_id;
16897                            }
16898                            chunk.text
16899                        })
16900                        .collect::<String>()
16901                        .into();
16902
16903                    drop(buffer);
16904
16905                    // Position the selection in the rename editor so that it matches the current selection.
16906                    this.show_local_selections = false;
16907                    let rename_editor = cx.new(|cx| {
16908                        let mut editor = Editor::single_line(window, cx);
16909                        editor.buffer.update(cx, |buffer, cx| {
16910                            buffer.edit([(0..0, old_name.clone())], None, cx)
16911                        });
16912                        let rename_selection_range = match cursor_offset_in_rename_range
16913                            .cmp(&cursor_offset_in_rename_range_end)
16914                        {
16915                            Ordering::Equal => {
16916                                editor.select_all(&SelectAll, window, cx);
16917                                return editor;
16918                            }
16919                            Ordering::Less => {
16920                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16921                            }
16922                            Ordering::Greater => {
16923                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16924                            }
16925                        };
16926                        if rename_selection_range.end > old_name.len() {
16927                            editor.select_all(&SelectAll, window, cx);
16928                        } else {
16929                            editor.change_selections(Default::default(), window, cx, |s| {
16930                                s.select_ranges([rename_selection_range]);
16931                            });
16932                        }
16933                        editor
16934                    });
16935                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16936                        if e == &EditorEvent::Focused {
16937                            cx.emit(EditorEvent::FocusedIn)
16938                        }
16939                    })
16940                    .detach();
16941
16942                    let write_highlights =
16943                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16944                    let read_highlights =
16945                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16946                    let ranges = write_highlights
16947                        .iter()
16948                        .flat_map(|(_, ranges)| ranges.iter())
16949                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16950                        .cloned()
16951                        .collect();
16952
16953                    this.highlight_text::<Rename>(
16954                        ranges,
16955                        HighlightStyle {
16956                            fade_out: Some(0.6),
16957                            ..Default::default()
16958                        },
16959                        cx,
16960                    );
16961                    let rename_focus_handle = rename_editor.focus_handle(cx);
16962                    window.focus(&rename_focus_handle);
16963                    let block_id = this.insert_blocks(
16964                        [BlockProperties {
16965                            style: BlockStyle::Flex,
16966                            placement: BlockPlacement::Below(range.start),
16967                            height: Some(1),
16968                            render: Arc::new({
16969                                let rename_editor = rename_editor.clone();
16970                                move |cx: &mut BlockContext| {
16971                                    let mut text_style = cx.editor_style.text.clone();
16972                                    if let Some(highlight_style) = old_highlight_id
16973                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16974                                    {
16975                                        text_style = text_style.highlight(highlight_style);
16976                                    }
16977                                    div()
16978                                        .block_mouse_except_scroll()
16979                                        .pl(cx.anchor_x)
16980                                        .child(EditorElement::new(
16981                                            &rename_editor,
16982                                            EditorStyle {
16983                                                background: cx.theme().system().transparent,
16984                                                local_player: cx.editor_style.local_player,
16985                                                text: text_style,
16986                                                scrollbar_width: cx.editor_style.scrollbar_width,
16987                                                syntax: cx.editor_style.syntax.clone(),
16988                                                status: cx.editor_style.status.clone(),
16989                                                inlay_hints_style: HighlightStyle {
16990                                                    font_weight: Some(FontWeight::BOLD),
16991                                                    ..make_inlay_hints_style(cx.app)
16992                                                },
16993                                                edit_prediction_styles: make_suggestion_styles(
16994                                                    cx.app,
16995                                                ),
16996                                                ..EditorStyle::default()
16997                                            },
16998                                        ))
16999                                        .into_any_element()
17000                                }
17001                            }),
17002                            priority: 0,
17003                        }],
17004                        Some(Autoscroll::fit()),
17005                        cx,
17006                    )[0];
17007                    this.pending_rename = Some(RenameState {
17008                        range,
17009                        old_name,
17010                        editor: rename_editor,
17011                        block_id,
17012                    });
17013                })?;
17014            }
17015
17016            Ok(())
17017        }))
17018    }
17019
17020    pub fn confirm_rename(
17021        &mut self,
17022        _: &ConfirmRename,
17023        window: &mut Window,
17024        cx: &mut Context<Self>,
17025    ) -> Option<Task<Result<()>>> {
17026        let rename = self.take_rename(false, window, cx)?;
17027        let workspace = self.workspace()?.downgrade();
17028        let (buffer, start) = self
17029            .buffer
17030            .read(cx)
17031            .text_anchor_for_position(rename.range.start, cx)?;
17032        let (end_buffer, _) = self
17033            .buffer
17034            .read(cx)
17035            .text_anchor_for_position(rename.range.end, cx)?;
17036        if buffer != end_buffer {
17037            return None;
17038        }
17039
17040        let old_name = rename.old_name;
17041        let new_name = rename.editor.read(cx).text(cx);
17042
17043        let rename = self.semantics_provider.as_ref()?.perform_rename(
17044            &buffer,
17045            start,
17046            new_name.clone(),
17047            cx,
17048        )?;
17049
17050        Some(cx.spawn_in(window, async move |editor, cx| {
17051            let project_transaction = rename.await?;
17052            Self::open_project_transaction(
17053                &editor,
17054                workspace,
17055                project_transaction,
17056                format!("Rename: {}{}", old_name, new_name),
17057                cx,
17058            )
17059            .await?;
17060
17061            editor.update(cx, |editor, cx| {
17062                editor.refresh_document_highlights(cx);
17063            })?;
17064            Ok(())
17065        }))
17066    }
17067
17068    fn take_rename(
17069        &mut self,
17070        moving_cursor: bool,
17071        window: &mut Window,
17072        cx: &mut Context<Self>,
17073    ) -> Option<RenameState> {
17074        let rename = self.pending_rename.take()?;
17075        if rename.editor.focus_handle(cx).is_focused(window) {
17076            window.focus(&self.focus_handle);
17077        }
17078
17079        self.remove_blocks(
17080            [rename.block_id].into_iter().collect(),
17081            Some(Autoscroll::fit()),
17082            cx,
17083        );
17084        self.clear_highlights::<Rename>(cx);
17085        self.show_local_selections = true;
17086
17087        if moving_cursor {
17088            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17089                editor.selections.newest::<usize>(cx).head()
17090            });
17091
17092            // Update the selection to match the position of the selection inside
17093            // the rename editor.
17094            let snapshot = self.buffer.read(cx).read(cx);
17095            let rename_range = rename.range.to_offset(&snapshot);
17096            let cursor_in_editor = snapshot
17097                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17098                .min(rename_range.end);
17099            drop(snapshot);
17100
17101            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17102                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17103            });
17104        } else {
17105            self.refresh_document_highlights(cx);
17106        }
17107
17108        Some(rename)
17109    }
17110
17111    pub fn pending_rename(&self) -> Option<&RenameState> {
17112        self.pending_rename.as_ref()
17113    }
17114
17115    fn format(
17116        &mut self,
17117        _: &Format,
17118        window: &mut Window,
17119        cx: &mut Context<Self>,
17120    ) -> Option<Task<Result<()>>> {
17121        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17122
17123        let project = match &self.project {
17124            Some(project) => project.clone(),
17125            None => return None,
17126        };
17127
17128        Some(self.perform_format(
17129            project,
17130            FormatTrigger::Manual,
17131            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17132            window,
17133            cx,
17134        ))
17135    }
17136
17137    fn format_selections(
17138        &mut self,
17139        _: &FormatSelections,
17140        window: &mut Window,
17141        cx: &mut Context<Self>,
17142    ) -> Option<Task<Result<()>>> {
17143        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17144
17145        let project = match &self.project {
17146            Some(project) => project.clone(),
17147            None => return None,
17148        };
17149
17150        let ranges = self
17151            .selections
17152            .all_adjusted(cx)
17153            .into_iter()
17154            .map(|selection| selection.range())
17155            .collect_vec();
17156
17157        Some(self.perform_format(
17158            project,
17159            FormatTrigger::Manual,
17160            FormatTarget::Ranges(ranges),
17161            window,
17162            cx,
17163        ))
17164    }
17165
17166    fn perform_format(
17167        &mut self,
17168        project: Entity<Project>,
17169        trigger: FormatTrigger,
17170        target: FormatTarget,
17171        window: &mut Window,
17172        cx: &mut Context<Self>,
17173    ) -> Task<Result<()>> {
17174        let buffer = self.buffer.clone();
17175        let (buffers, target) = match target {
17176            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17177            FormatTarget::Ranges(selection_ranges) => {
17178                let multi_buffer = buffer.read(cx);
17179                let snapshot = multi_buffer.read(cx);
17180                let mut buffers = HashSet::default();
17181                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17182                    BTreeMap::new();
17183                for selection_range in selection_ranges {
17184                    for (buffer, buffer_range, _) in
17185                        snapshot.range_to_buffer_ranges(selection_range)
17186                    {
17187                        let buffer_id = buffer.remote_id();
17188                        let start = buffer.anchor_before(buffer_range.start);
17189                        let end = buffer.anchor_after(buffer_range.end);
17190                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17191                        buffer_id_to_ranges
17192                            .entry(buffer_id)
17193                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17194                            .or_insert_with(|| vec![start..end]);
17195                    }
17196                }
17197                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17198            }
17199        };
17200
17201        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17202        let selections_prev = transaction_id_prev
17203            .and_then(|transaction_id_prev| {
17204                // default to selections as they were after the last edit, if we have them,
17205                // instead of how they are now.
17206                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17207                // will take you back to where you made the last edit, instead of staying where you scrolled
17208                self.selection_history
17209                    .transaction(transaction_id_prev)
17210                    .map(|t| t.0.clone())
17211            })
17212            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17213
17214        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17215        let format = project.update(cx, |project, cx| {
17216            project.format(buffers, target, true, trigger, cx)
17217        });
17218
17219        cx.spawn_in(window, async move |editor, cx| {
17220            let transaction = futures::select_biased! {
17221                transaction = format.log_err().fuse() => transaction,
17222                () = timeout => {
17223                    log::warn!("timed out waiting for formatting");
17224                    None
17225                }
17226            };
17227
17228            buffer
17229                .update(cx, |buffer, cx| {
17230                    if let Some(transaction) = transaction
17231                        && !buffer.is_singleton()
17232                    {
17233                        buffer.push_transaction(&transaction.0, cx);
17234                    }
17235                    cx.notify();
17236                })
17237                .ok();
17238
17239            if let Some(transaction_id_now) =
17240                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17241            {
17242                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17243                if has_new_transaction {
17244                    _ = editor.update(cx, |editor, _| {
17245                        editor
17246                            .selection_history
17247                            .insert_transaction(transaction_id_now, selections_prev);
17248                    });
17249                }
17250            }
17251
17252            Ok(())
17253        })
17254    }
17255
17256    fn organize_imports(
17257        &mut self,
17258        _: &OrganizeImports,
17259        window: &mut Window,
17260        cx: &mut Context<Self>,
17261    ) -> Option<Task<Result<()>>> {
17262        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17263        let project = match &self.project {
17264            Some(project) => project.clone(),
17265            None => return None,
17266        };
17267        Some(self.perform_code_action_kind(
17268            project,
17269            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17270            window,
17271            cx,
17272        ))
17273    }
17274
17275    fn perform_code_action_kind(
17276        &mut self,
17277        project: Entity<Project>,
17278        kind: CodeActionKind,
17279        window: &mut Window,
17280        cx: &mut Context<Self>,
17281    ) -> Task<Result<()>> {
17282        let buffer = self.buffer.clone();
17283        let buffers = buffer.read(cx).all_buffers();
17284        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17285        let apply_action = project.update(cx, |project, cx| {
17286            project.apply_code_action_kind(buffers, kind, true, cx)
17287        });
17288        cx.spawn_in(window, async move |_, cx| {
17289            let transaction = futures::select_biased! {
17290                () = timeout => {
17291                    log::warn!("timed out waiting for executing code action");
17292                    None
17293                }
17294                transaction = apply_action.log_err().fuse() => transaction,
17295            };
17296            buffer
17297                .update(cx, |buffer, cx| {
17298                    // check if we need this
17299                    if let Some(transaction) = transaction
17300                        && !buffer.is_singleton()
17301                    {
17302                        buffer.push_transaction(&transaction.0, cx);
17303                    }
17304                    cx.notify();
17305                })
17306                .ok();
17307            Ok(())
17308        })
17309    }
17310
17311    pub fn restart_language_server(
17312        &mut self,
17313        _: &RestartLanguageServer,
17314        _: &mut Window,
17315        cx: &mut Context<Self>,
17316    ) {
17317        if let Some(project) = self.project.clone() {
17318            self.buffer.update(cx, |multi_buffer, cx| {
17319                project.update(cx, |project, cx| {
17320                    project.restart_language_servers_for_buffers(
17321                        multi_buffer.all_buffers().into_iter().collect(),
17322                        HashSet::default(),
17323                        cx,
17324                    );
17325                });
17326            })
17327        }
17328    }
17329
17330    pub fn stop_language_server(
17331        &mut self,
17332        _: &StopLanguageServer,
17333        _: &mut Window,
17334        cx: &mut Context<Self>,
17335    ) {
17336        if let Some(project) = self.project.clone() {
17337            self.buffer.update(cx, |multi_buffer, cx| {
17338                project.update(cx, |project, cx| {
17339                    project.stop_language_servers_for_buffers(
17340                        multi_buffer.all_buffers().into_iter().collect(),
17341                        HashSet::default(),
17342                        cx,
17343                    );
17344                    cx.emit(project::Event::RefreshInlayHints);
17345                });
17346            });
17347        }
17348    }
17349
17350    fn cancel_language_server_work(
17351        workspace: &mut Workspace,
17352        _: &actions::CancelLanguageServerWork,
17353        _: &mut Window,
17354        cx: &mut Context<Workspace>,
17355    ) {
17356        let project = workspace.project();
17357        let buffers = workspace
17358            .active_item(cx)
17359            .and_then(|item| item.act_as::<Editor>(cx))
17360            .map_or(HashSet::default(), |editor| {
17361                editor.read(cx).buffer.read(cx).all_buffers()
17362            });
17363        project.update(cx, |project, cx| {
17364            project.cancel_language_server_work_for_buffers(buffers, cx);
17365        });
17366    }
17367
17368    fn show_character_palette(
17369        &mut self,
17370        _: &ShowCharacterPalette,
17371        window: &mut Window,
17372        _: &mut Context<Self>,
17373    ) {
17374        window.show_character_palette();
17375    }
17376
17377    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17378        if !self.diagnostics_enabled() {
17379            return;
17380        }
17381
17382        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17383            let buffer = self.buffer.read(cx).snapshot(cx);
17384            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17385            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17386            let is_valid = buffer
17387                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17388                .any(|entry| {
17389                    entry.diagnostic.is_primary
17390                        && !entry.range.is_empty()
17391                        && entry.range.start == primary_range_start
17392                        && entry.diagnostic.message == active_diagnostics.active_message
17393                });
17394
17395            if !is_valid {
17396                self.dismiss_diagnostics(cx);
17397            }
17398        }
17399    }
17400
17401    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17402        match &self.active_diagnostics {
17403            ActiveDiagnostic::Group(group) => Some(group),
17404            _ => None,
17405        }
17406    }
17407
17408    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17409        if !self.diagnostics_enabled() {
17410            return;
17411        }
17412        self.dismiss_diagnostics(cx);
17413        self.active_diagnostics = ActiveDiagnostic::All;
17414    }
17415
17416    fn activate_diagnostics(
17417        &mut self,
17418        buffer_id: BufferId,
17419        diagnostic: DiagnosticEntry<usize>,
17420        window: &mut Window,
17421        cx: &mut Context<Self>,
17422    ) {
17423        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17424            return;
17425        }
17426        self.dismiss_diagnostics(cx);
17427        let snapshot = self.snapshot(window, cx);
17428        let buffer = self.buffer.read(cx).snapshot(cx);
17429        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17430            return;
17431        };
17432
17433        let diagnostic_group = buffer
17434            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17435            .collect::<Vec<_>>();
17436
17437        let blocks =
17438            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17439
17440        let blocks = self.display_map.update(cx, |display_map, cx| {
17441            display_map.insert_blocks(blocks, cx).into_iter().collect()
17442        });
17443        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17444            active_range: buffer.anchor_before(diagnostic.range.start)
17445                ..buffer.anchor_after(diagnostic.range.end),
17446            active_message: diagnostic.diagnostic.message.clone(),
17447            group_id: diagnostic.diagnostic.group_id,
17448            blocks,
17449        });
17450        cx.notify();
17451    }
17452
17453    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17454        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17455            return;
17456        };
17457
17458        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17459        if let ActiveDiagnostic::Group(group) = prev {
17460            self.display_map.update(cx, |display_map, cx| {
17461                display_map.remove_blocks(group.blocks, cx);
17462            });
17463            cx.notify();
17464        }
17465    }
17466
17467    /// Disable inline diagnostics rendering for this editor.
17468    pub fn disable_inline_diagnostics(&mut self) {
17469        self.inline_diagnostics_enabled = false;
17470        self.inline_diagnostics_update = Task::ready(());
17471        self.inline_diagnostics.clear();
17472    }
17473
17474    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17475        self.diagnostics_enabled = false;
17476        self.dismiss_diagnostics(cx);
17477        self.inline_diagnostics_update = Task::ready(());
17478        self.inline_diagnostics.clear();
17479    }
17480
17481    pub fn disable_word_completions(&mut self) {
17482        self.word_completions_enabled = false;
17483    }
17484
17485    pub fn diagnostics_enabled(&self) -> bool {
17486        self.diagnostics_enabled && self.mode.is_full()
17487    }
17488
17489    pub fn inline_diagnostics_enabled(&self) -> bool {
17490        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17491    }
17492
17493    pub fn show_inline_diagnostics(&self) -> bool {
17494        self.show_inline_diagnostics
17495    }
17496
17497    pub fn toggle_inline_diagnostics(
17498        &mut self,
17499        _: &ToggleInlineDiagnostics,
17500        window: &mut Window,
17501        cx: &mut Context<Editor>,
17502    ) {
17503        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17504        self.refresh_inline_diagnostics(false, window, cx);
17505    }
17506
17507    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17508        self.diagnostics_max_severity = severity;
17509        self.display_map.update(cx, |display_map, _| {
17510            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17511        });
17512    }
17513
17514    pub fn toggle_diagnostics(
17515        &mut self,
17516        _: &ToggleDiagnostics,
17517        window: &mut Window,
17518        cx: &mut Context<Editor>,
17519    ) {
17520        if !self.diagnostics_enabled() {
17521            return;
17522        }
17523
17524        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17525            EditorSettings::get_global(cx)
17526                .diagnostics_max_severity
17527                .filter(|severity| severity != &DiagnosticSeverity::Off)
17528                .unwrap_or(DiagnosticSeverity::Hint)
17529        } else {
17530            DiagnosticSeverity::Off
17531        };
17532        self.set_max_diagnostics_severity(new_severity, cx);
17533        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17534            self.active_diagnostics = ActiveDiagnostic::None;
17535            self.inline_diagnostics_update = Task::ready(());
17536            self.inline_diagnostics.clear();
17537        } else {
17538            self.refresh_inline_diagnostics(false, window, cx);
17539        }
17540
17541        cx.notify();
17542    }
17543
17544    pub fn toggle_minimap(
17545        &mut self,
17546        _: &ToggleMinimap,
17547        window: &mut Window,
17548        cx: &mut Context<Editor>,
17549    ) {
17550        if self.supports_minimap(cx) {
17551            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17552        }
17553    }
17554
17555    fn refresh_inline_diagnostics(
17556        &mut self,
17557        debounce: bool,
17558        window: &mut Window,
17559        cx: &mut Context<Self>,
17560    ) {
17561        let max_severity = ProjectSettings::get_global(cx)
17562            .diagnostics
17563            .inline
17564            .max_severity
17565            .unwrap_or(self.diagnostics_max_severity);
17566
17567        if !self.inline_diagnostics_enabled()
17568            || !self.show_inline_diagnostics
17569            || max_severity == DiagnosticSeverity::Off
17570        {
17571            self.inline_diagnostics_update = Task::ready(());
17572            self.inline_diagnostics.clear();
17573            return;
17574        }
17575
17576        let debounce_ms = ProjectSettings::get_global(cx)
17577            .diagnostics
17578            .inline
17579            .update_debounce_ms;
17580        let debounce = if debounce && debounce_ms > 0 {
17581            Some(Duration::from_millis(debounce_ms))
17582        } else {
17583            None
17584        };
17585        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17586            if let Some(debounce) = debounce {
17587                cx.background_executor().timer(debounce).await;
17588            }
17589            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17590                editor
17591                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17592                    .ok()
17593            }) else {
17594                return;
17595            };
17596
17597            let new_inline_diagnostics = cx
17598                .background_spawn(async move {
17599                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17600                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17601                        let message = diagnostic_entry
17602                            .diagnostic
17603                            .message
17604                            .split_once('\n')
17605                            .map(|(line, _)| line)
17606                            .map(SharedString::new)
17607                            .unwrap_or_else(|| {
17608                                SharedString::from(diagnostic_entry.diagnostic.message)
17609                            });
17610                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17611                        let (Ok(i) | Err(i)) = inline_diagnostics
17612                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17613                        inline_diagnostics.insert(
17614                            i,
17615                            (
17616                                start_anchor,
17617                                InlineDiagnostic {
17618                                    message,
17619                                    group_id: diagnostic_entry.diagnostic.group_id,
17620                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17621                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17622                                    severity: diagnostic_entry.diagnostic.severity,
17623                                },
17624                            ),
17625                        );
17626                    }
17627                    inline_diagnostics
17628                })
17629                .await;
17630
17631            editor
17632                .update(cx, |editor, cx| {
17633                    editor.inline_diagnostics = new_inline_diagnostics;
17634                    cx.notify();
17635                })
17636                .ok();
17637        });
17638    }
17639
17640    fn pull_diagnostics(
17641        &mut self,
17642        buffer_id: Option<BufferId>,
17643        window: &Window,
17644        cx: &mut Context<Self>,
17645    ) -> Option<()> {
17646        if !self.mode().is_full() {
17647            return None;
17648        }
17649        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17650            .diagnostics
17651            .lsp_pull_diagnostics;
17652        if !pull_diagnostics_settings.enabled {
17653            return None;
17654        }
17655        let project = self.project()?.downgrade();
17656        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17657        let mut buffers = self.buffer.read(cx).all_buffers();
17658        if let Some(buffer_id) = buffer_id {
17659            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17660        }
17661
17662        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17663            cx.background_executor().timer(debounce).await;
17664
17665            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17666                buffers
17667                    .into_iter()
17668                    .filter_map(|buffer| {
17669                        project
17670                            .update(cx, |project, cx| {
17671                                project.lsp_store().update(cx, |lsp_store, cx| {
17672                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17673                                })
17674                            })
17675                            .ok()
17676                    })
17677                    .collect::<FuturesUnordered<_>>()
17678            }) else {
17679                return;
17680            };
17681
17682            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17683                match pull_task {
17684                    Ok(()) => {
17685                        if editor
17686                            .update_in(cx, |editor, window, cx| {
17687                                editor.update_diagnostics_state(window, cx);
17688                            })
17689                            .is_err()
17690                        {
17691                            return;
17692                        }
17693                    }
17694                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17695                }
17696            }
17697        });
17698
17699        Some(())
17700    }
17701
17702    pub fn set_selections_from_remote(
17703        &mut self,
17704        selections: Vec<Selection<Anchor>>,
17705        pending_selection: Option<Selection<Anchor>>,
17706        window: &mut Window,
17707        cx: &mut Context<Self>,
17708    ) {
17709        let old_cursor_position = self.selections.newest_anchor().head();
17710        self.selections.change_with(cx, |s| {
17711            s.select_anchors(selections);
17712            if let Some(pending_selection) = pending_selection {
17713                s.set_pending(pending_selection, SelectMode::Character);
17714            } else {
17715                s.clear_pending();
17716            }
17717        });
17718        self.selections_did_change(
17719            false,
17720            &old_cursor_position,
17721            SelectionEffects::default(),
17722            window,
17723            cx,
17724        );
17725    }
17726
17727    pub fn transact(
17728        &mut self,
17729        window: &mut Window,
17730        cx: &mut Context<Self>,
17731        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17732    ) -> Option<TransactionId> {
17733        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17734            this.start_transaction_at(Instant::now(), window, cx);
17735            update(this, window, cx);
17736            this.end_transaction_at(Instant::now(), cx)
17737        })
17738    }
17739
17740    pub fn start_transaction_at(
17741        &mut self,
17742        now: Instant,
17743        window: &mut Window,
17744        cx: &mut Context<Self>,
17745    ) -> Option<TransactionId> {
17746        self.end_selection(window, cx);
17747        if let Some(tx_id) = self
17748            .buffer
17749            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17750        {
17751            self.selection_history
17752                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17753            cx.emit(EditorEvent::TransactionBegun {
17754                transaction_id: tx_id,
17755            });
17756            Some(tx_id)
17757        } else {
17758            None
17759        }
17760    }
17761
17762    pub fn end_transaction_at(
17763        &mut self,
17764        now: Instant,
17765        cx: &mut Context<Self>,
17766    ) -> Option<TransactionId> {
17767        if let Some(transaction_id) = self
17768            .buffer
17769            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17770        {
17771            if let Some((_, end_selections)) =
17772                self.selection_history.transaction_mut(transaction_id)
17773            {
17774                *end_selections = Some(self.selections.disjoint_anchors_arc());
17775            } else {
17776                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17777            }
17778
17779            cx.emit(EditorEvent::Edited { transaction_id });
17780            Some(transaction_id)
17781        } else {
17782            None
17783        }
17784    }
17785
17786    pub fn modify_transaction_selection_history(
17787        &mut self,
17788        transaction_id: TransactionId,
17789        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17790    ) -> bool {
17791        self.selection_history
17792            .transaction_mut(transaction_id)
17793            .map(modify)
17794            .is_some()
17795    }
17796
17797    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17798        if self.selection_mark_mode {
17799            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17800                s.move_with(|_, sel| {
17801                    sel.collapse_to(sel.head(), SelectionGoal::None);
17802                });
17803            })
17804        }
17805        self.selection_mark_mode = true;
17806        cx.notify();
17807    }
17808
17809    pub fn swap_selection_ends(
17810        &mut self,
17811        _: &actions::SwapSelectionEnds,
17812        window: &mut Window,
17813        cx: &mut Context<Self>,
17814    ) {
17815        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17816            s.move_with(|_, sel| {
17817                if sel.start != sel.end {
17818                    sel.reversed = !sel.reversed
17819                }
17820            });
17821        });
17822        self.request_autoscroll(Autoscroll::newest(), cx);
17823        cx.notify();
17824    }
17825
17826    pub fn toggle_focus(
17827        workspace: &mut Workspace,
17828        _: &actions::ToggleFocus,
17829        window: &mut Window,
17830        cx: &mut Context<Workspace>,
17831    ) {
17832        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17833            return;
17834        };
17835        workspace.activate_item(&item, true, true, window, cx);
17836    }
17837
17838    pub fn toggle_fold(
17839        &mut self,
17840        _: &actions::ToggleFold,
17841        window: &mut Window,
17842        cx: &mut Context<Self>,
17843    ) {
17844        if self.is_singleton(cx) {
17845            let selection = self.selections.newest::<Point>(cx);
17846
17847            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17848            let range = if selection.is_empty() {
17849                let point = selection.head().to_display_point(&display_map);
17850                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17851                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17852                    .to_point(&display_map);
17853                start..end
17854            } else {
17855                selection.range()
17856            };
17857            if display_map.folds_in_range(range).next().is_some() {
17858                self.unfold_lines(&Default::default(), window, cx)
17859            } else {
17860                self.fold(&Default::default(), window, cx)
17861            }
17862        } else {
17863            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17864            let buffer_ids: HashSet<_> = self
17865                .selections
17866                .disjoint_anchor_ranges()
17867                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17868                .collect();
17869
17870            let should_unfold = buffer_ids
17871                .iter()
17872                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17873
17874            for buffer_id in buffer_ids {
17875                if should_unfold {
17876                    self.unfold_buffer(buffer_id, cx);
17877                } else {
17878                    self.fold_buffer(buffer_id, cx);
17879                }
17880            }
17881        }
17882    }
17883
17884    pub fn toggle_fold_recursive(
17885        &mut self,
17886        _: &actions::ToggleFoldRecursive,
17887        window: &mut Window,
17888        cx: &mut Context<Self>,
17889    ) {
17890        let selection = self.selections.newest::<Point>(cx);
17891
17892        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17893        let range = if selection.is_empty() {
17894            let point = selection.head().to_display_point(&display_map);
17895            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17896            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17897                .to_point(&display_map);
17898            start..end
17899        } else {
17900            selection.range()
17901        };
17902        if display_map.folds_in_range(range).next().is_some() {
17903            self.unfold_recursive(&Default::default(), window, cx)
17904        } else {
17905            self.fold_recursive(&Default::default(), window, cx)
17906        }
17907    }
17908
17909    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17910        if self.is_singleton(cx) {
17911            let mut to_fold = Vec::new();
17912            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17913            let selections = self.selections.all_adjusted(cx);
17914
17915            for selection in selections {
17916                let range = selection.range().sorted();
17917                let buffer_start_row = range.start.row;
17918
17919                if range.start.row != range.end.row {
17920                    let mut found = false;
17921                    let mut row = range.start.row;
17922                    while row <= range.end.row {
17923                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17924                        {
17925                            found = true;
17926                            row = crease.range().end.row + 1;
17927                            to_fold.push(crease);
17928                        } else {
17929                            row += 1
17930                        }
17931                    }
17932                    if found {
17933                        continue;
17934                    }
17935                }
17936
17937                for row in (0..=range.start.row).rev() {
17938                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17939                        && crease.range().end.row >= buffer_start_row
17940                    {
17941                        to_fold.push(crease);
17942                        if row <= range.start.row {
17943                            break;
17944                        }
17945                    }
17946                }
17947            }
17948
17949            self.fold_creases(to_fold, true, window, cx);
17950        } else {
17951            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17952            let buffer_ids = self
17953                .selections
17954                .disjoint_anchor_ranges()
17955                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17956                .collect::<HashSet<_>>();
17957            for buffer_id in buffer_ids {
17958                self.fold_buffer(buffer_id, cx);
17959            }
17960        }
17961    }
17962
17963    pub fn toggle_fold_all(
17964        &mut self,
17965        _: &actions::ToggleFoldAll,
17966        window: &mut Window,
17967        cx: &mut Context<Self>,
17968    ) {
17969        if self.buffer.read(cx).is_singleton() {
17970            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17971            let has_folds = display_map
17972                .folds_in_range(0..display_map.buffer_snapshot.len())
17973                .next()
17974                .is_some();
17975
17976            if has_folds {
17977                self.unfold_all(&actions::UnfoldAll, window, cx);
17978            } else {
17979                self.fold_all(&actions::FoldAll, window, cx);
17980            }
17981        } else {
17982            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17983            let should_unfold = buffer_ids
17984                .iter()
17985                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17986
17987            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17988                editor
17989                    .update_in(cx, |editor, _, cx| {
17990                        for buffer_id in buffer_ids {
17991                            if should_unfold {
17992                                editor.unfold_buffer(buffer_id, cx);
17993                            } else {
17994                                editor.fold_buffer(buffer_id, cx);
17995                            }
17996                        }
17997                    })
17998                    .ok();
17999            });
18000        }
18001    }
18002
18003    fn fold_at_level(
18004        &mut self,
18005        fold_at: &FoldAtLevel,
18006        window: &mut Window,
18007        cx: &mut Context<Self>,
18008    ) {
18009        if !self.buffer.read(cx).is_singleton() {
18010            return;
18011        }
18012
18013        let fold_at_level = fold_at.0;
18014        let snapshot = self.buffer.read(cx).snapshot(cx);
18015        let mut to_fold = Vec::new();
18016        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18017
18018        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18019            while start_row < end_row {
18020                match self
18021                    .snapshot(window, cx)
18022                    .crease_for_buffer_row(MultiBufferRow(start_row))
18023                {
18024                    Some(crease) => {
18025                        let nested_start_row = crease.range().start.row + 1;
18026                        let nested_end_row = crease.range().end.row;
18027
18028                        if current_level < fold_at_level {
18029                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18030                        } else if current_level == fold_at_level {
18031                            to_fold.push(crease);
18032                        }
18033
18034                        start_row = nested_end_row + 1;
18035                    }
18036                    None => start_row += 1,
18037                }
18038            }
18039        }
18040
18041        self.fold_creases(to_fold, true, window, cx);
18042    }
18043
18044    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18045        if self.buffer.read(cx).is_singleton() {
18046            let mut fold_ranges = Vec::new();
18047            let snapshot = self.buffer.read(cx).snapshot(cx);
18048
18049            for row in 0..snapshot.max_row().0 {
18050                if let Some(foldable_range) = self
18051                    .snapshot(window, cx)
18052                    .crease_for_buffer_row(MultiBufferRow(row))
18053                {
18054                    fold_ranges.push(foldable_range);
18055                }
18056            }
18057
18058            self.fold_creases(fold_ranges, true, window, cx);
18059        } else {
18060            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18061                editor
18062                    .update_in(cx, |editor, _, cx| {
18063                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18064                            editor.fold_buffer(buffer_id, cx);
18065                        }
18066                    })
18067                    .ok();
18068            });
18069        }
18070    }
18071
18072    pub fn fold_function_bodies(
18073        &mut self,
18074        _: &actions::FoldFunctionBodies,
18075        window: &mut Window,
18076        cx: &mut Context<Self>,
18077    ) {
18078        let snapshot = self.buffer.read(cx).snapshot(cx);
18079
18080        let ranges = snapshot
18081            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18082            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18083            .collect::<Vec<_>>();
18084
18085        let creases = ranges
18086            .into_iter()
18087            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18088            .collect();
18089
18090        self.fold_creases(creases, true, window, cx);
18091    }
18092
18093    pub fn fold_recursive(
18094        &mut self,
18095        _: &actions::FoldRecursive,
18096        window: &mut Window,
18097        cx: &mut Context<Self>,
18098    ) {
18099        let mut to_fold = Vec::new();
18100        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18101        let selections = self.selections.all_adjusted(cx);
18102
18103        for selection in selections {
18104            let range = selection.range().sorted();
18105            let buffer_start_row = range.start.row;
18106
18107            if range.start.row != range.end.row {
18108                let mut found = false;
18109                for row in range.start.row..=range.end.row {
18110                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18111                        found = true;
18112                        to_fold.push(crease);
18113                    }
18114                }
18115                if found {
18116                    continue;
18117                }
18118            }
18119
18120            for row in (0..=range.start.row).rev() {
18121                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18122                    if crease.range().end.row >= buffer_start_row {
18123                        to_fold.push(crease);
18124                    } else {
18125                        break;
18126                    }
18127                }
18128            }
18129        }
18130
18131        self.fold_creases(to_fold, true, window, cx);
18132    }
18133
18134    pub fn fold_at(
18135        &mut self,
18136        buffer_row: MultiBufferRow,
18137        window: &mut Window,
18138        cx: &mut Context<Self>,
18139    ) {
18140        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18141
18142        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18143            let autoscroll = self
18144                .selections
18145                .all::<Point>(cx)
18146                .iter()
18147                .any(|selection| crease.range().overlaps(&selection.range()));
18148
18149            self.fold_creases(vec![crease], autoscroll, window, cx);
18150        }
18151    }
18152
18153    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18154        if self.is_singleton(cx) {
18155            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18156            let buffer = &display_map.buffer_snapshot;
18157            let selections = self.selections.all::<Point>(cx);
18158            let ranges = selections
18159                .iter()
18160                .map(|s| {
18161                    let range = s.display_range(&display_map).sorted();
18162                    let mut start = range.start.to_point(&display_map);
18163                    let mut end = range.end.to_point(&display_map);
18164                    start.column = 0;
18165                    end.column = buffer.line_len(MultiBufferRow(end.row));
18166                    start..end
18167                })
18168                .collect::<Vec<_>>();
18169
18170            self.unfold_ranges(&ranges, true, true, cx);
18171        } else {
18172            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18173            let buffer_ids = self
18174                .selections
18175                .disjoint_anchor_ranges()
18176                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18177                .collect::<HashSet<_>>();
18178            for buffer_id in buffer_ids {
18179                self.unfold_buffer(buffer_id, cx);
18180            }
18181        }
18182    }
18183
18184    pub fn unfold_recursive(
18185        &mut self,
18186        _: &UnfoldRecursive,
18187        _window: &mut Window,
18188        cx: &mut Context<Self>,
18189    ) {
18190        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18191        let selections = self.selections.all::<Point>(cx);
18192        let ranges = selections
18193            .iter()
18194            .map(|s| {
18195                let mut range = s.display_range(&display_map).sorted();
18196                *range.start.column_mut() = 0;
18197                *range.end.column_mut() = display_map.line_len(range.end.row());
18198                let start = range.start.to_point(&display_map);
18199                let end = range.end.to_point(&display_map);
18200                start..end
18201            })
18202            .collect::<Vec<_>>();
18203
18204        self.unfold_ranges(&ranges, true, true, cx);
18205    }
18206
18207    pub fn unfold_at(
18208        &mut self,
18209        buffer_row: MultiBufferRow,
18210        _window: &mut Window,
18211        cx: &mut Context<Self>,
18212    ) {
18213        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18214
18215        let intersection_range = Point::new(buffer_row.0, 0)
18216            ..Point::new(
18217                buffer_row.0,
18218                display_map.buffer_snapshot.line_len(buffer_row),
18219            );
18220
18221        let autoscroll = self
18222            .selections
18223            .all::<Point>(cx)
18224            .iter()
18225            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18226
18227        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18228    }
18229
18230    pub fn unfold_all(
18231        &mut self,
18232        _: &actions::UnfoldAll,
18233        _window: &mut Window,
18234        cx: &mut Context<Self>,
18235    ) {
18236        if self.buffer.read(cx).is_singleton() {
18237            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18238            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18239        } else {
18240            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18241                editor
18242                    .update(cx, |editor, cx| {
18243                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18244                            editor.unfold_buffer(buffer_id, cx);
18245                        }
18246                    })
18247                    .ok();
18248            });
18249        }
18250    }
18251
18252    pub fn fold_selected_ranges(
18253        &mut self,
18254        _: &FoldSelectedRanges,
18255        window: &mut Window,
18256        cx: &mut Context<Self>,
18257    ) {
18258        let selections = self.selections.all_adjusted(cx);
18259        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18260        let ranges = selections
18261            .into_iter()
18262            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18263            .collect::<Vec<_>>();
18264        self.fold_creases(ranges, true, window, cx);
18265    }
18266
18267    pub fn fold_ranges<T: ToOffset + Clone>(
18268        &mut self,
18269        ranges: Vec<Range<T>>,
18270        auto_scroll: bool,
18271        window: &mut Window,
18272        cx: &mut Context<Self>,
18273    ) {
18274        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18275        let ranges = ranges
18276            .into_iter()
18277            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18278            .collect::<Vec<_>>();
18279        self.fold_creases(ranges, auto_scroll, window, cx);
18280    }
18281
18282    pub fn fold_creases<T: ToOffset + Clone>(
18283        &mut self,
18284        creases: Vec<Crease<T>>,
18285        auto_scroll: bool,
18286        _window: &mut Window,
18287        cx: &mut Context<Self>,
18288    ) {
18289        if creases.is_empty() {
18290            return;
18291        }
18292
18293        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18294
18295        if auto_scroll {
18296            self.request_autoscroll(Autoscroll::fit(), cx);
18297        }
18298
18299        cx.notify();
18300
18301        self.scrollbar_marker_state.dirty = true;
18302        self.folds_did_change(cx);
18303    }
18304
18305    /// Removes any folds whose ranges intersect any of the given ranges.
18306    pub fn unfold_ranges<T: ToOffset + Clone>(
18307        &mut self,
18308        ranges: &[Range<T>],
18309        inclusive: bool,
18310        auto_scroll: bool,
18311        cx: &mut Context<Self>,
18312    ) {
18313        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18314            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18315        });
18316        self.folds_did_change(cx);
18317    }
18318
18319    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18320        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18321            return;
18322        }
18323        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18324        self.display_map.update(cx, |display_map, cx| {
18325            display_map.fold_buffers([buffer_id], cx)
18326        });
18327        cx.emit(EditorEvent::BufferFoldToggled {
18328            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18329            folded: true,
18330        });
18331        cx.notify();
18332    }
18333
18334    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18335        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18336            return;
18337        }
18338        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18339        self.display_map.update(cx, |display_map, cx| {
18340            display_map.unfold_buffers([buffer_id], cx);
18341        });
18342        cx.emit(EditorEvent::BufferFoldToggled {
18343            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18344            folded: false,
18345        });
18346        cx.notify();
18347    }
18348
18349    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18350        self.display_map.read(cx).is_buffer_folded(buffer)
18351    }
18352
18353    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18354        self.display_map.read(cx).folded_buffers()
18355    }
18356
18357    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18358        self.display_map.update(cx, |display_map, cx| {
18359            display_map.disable_header_for_buffer(buffer_id, cx);
18360        });
18361        cx.notify();
18362    }
18363
18364    /// Removes any folds with the given ranges.
18365    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18366        &mut self,
18367        ranges: &[Range<T>],
18368        type_id: TypeId,
18369        auto_scroll: bool,
18370        cx: &mut Context<Self>,
18371    ) {
18372        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18373            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18374        });
18375        self.folds_did_change(cx);
18376    }
18377
18378    fn remove_folds_with<T: ToOffset + Clone>(
18379        &mut self,
18380        ranges: &[Range<T>],
18381        auto_scroll: bool,
18382        cx: &mut Context<Self>,
18383        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18384    ) {
18385        if ranges.is_empty() {
18386            return;
18387        }
18388
18389        let mut buffers_affected = HashSet::default();
18390        let multi_buffer = self.buffer().read(cx);
18391        for range in ranges {
18392            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18393                buffers_affected.insert(buffer.read(cx).remote_id());
18394            };
18395        }
18396
18397        self.display_map.update(cx, update);
18398
18399        if auto_scroll {
18400            self.request_autoscroll(Autoscroll::fit(), cx);
18401        }
18402
18403        cx.notify();
18404        self.scrollbar_marker_state.dirty = true;
18405        self.active_indent_guides_state.dirty = true;
18406    }
18407
18408    pub fn update_renderer_widths(
18409        &mut self,
18410        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18411        cx: &mut Context<Self>,
18412    ) -> bool {
18413        self.display_map
18414            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18415    }
18416
18417    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18418        self.display_map.read(cx).fold_placeholder.clone()
18419    }
18420
18421    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18422        self.buffer.update(cx, |buffer, cx| {
18423            buffer.set_all_diff_hunks_expanded(cx);
18424        });
18425    }
18426
18427    pub fn expand_all_diff_hunks(
18428        &mut self,
18429        _: &ExpandAllDiffHunks,
18430        _window: &mut Window,
18431        cx: &mut Context<Self>,
18432    ) {
18433        self.buffer.update(cx, |buffer, cx| {
18434            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18435        });
18436    }
18437
18438    pub fn toggle_selected_diff_hunks(
18439        &mut self,
18440        _: &ToggleSelectedDiffHunks,
18441        _window: &mut Window,
18442        cx: &mut Context<Self>,
18443    ) {
18444        let ranges: Vec<_> = self
18445            .selections
18446            .disjoint_anchors()
18447            .iter()
18448            .map(|s| s.range())
18449            .collect();
18450        self.toggle_diff_hunks_in_ranges(ranges, cx);
18451    }
18452
18453    pub fn diff_hunks_in_ranges<'a>(
18454        &'a self,
18455        ranges: &'a [Range<Anchor>],
18456        buffer: &'a MultiBufferSnapshot,
18457    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18458        ranges.iter().flat_map(move |range| {
18459            let end_excerpt_id = range.end.excerpt_id;
18460            let range = range.to_point(buffer);
18461            let mut peek_end = range.end;
18462            if range.end.row < buffer.max_row().0 {
18463                peek_end = Point::new(range.end.row + 1, 0);
18464            }
18465            buffer
18466                .diff_hunks_in_range(range.start..peek_end)
18467                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18468        })
18469    }
18470
18471    pub fn has_stageable_diff_hunks_in_ranges(
18472        &self,
18473        ranges: &[Range<Anchor>],
18474        snapshot: &MultiBufferSnapshot,
18475    ) -> bool {
18476        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18477        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18478    }
18479
18480    pub fn toggle_staged_selected_diff_hunks(
18481        &mut self,
18482        _: &::git::ToggleStaged,
18483        _: &mut Window,
18484        cx: &mut Context<Self>,
18485    ) {
18486        let snapshot = self.buffer.read(cx).snapshot(cx);
18487        let ranges: Vec<_> = self
18488            .selections
18489            .disjoint_anchors()
18490            .iter()
18491            .map(|s| s.range())
18492            .collect();
18493        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18494        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18495    }
18496
18497    pub fn set_render_diff_hunk_controls(
18498        &mut self,
18499        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18500        cx: &mut Context<Self>,
18501    ) {
18502        self.render_diff_hunk_controls = render_diff_hunk_controls;
18503        cx.notify();
18504    }
18505
18506    pub fn stage_and_next(
18507        &mut self,
18508        _: &::git::StageAndNext,
18509        window: &mut Window,
18510        cx: &mut Context<Self>,
18511    ) {
18512        self.do_stage_or_unstage_and_next(true, window, cx);
18513    }
18514
18515    pub fn unstage_and_next(
18516        &mut self,
18517        _: &::git::UnstageAndNext,
18518        window: &mut Window,
18519        cx: &mut Context<Self>,
18520    ) {
18521        self.do_stage_or_unstage_and_next(false, window, cx);
18522    }
18523
18524    pub fn stage_or_unstage_diff_hunks(
18525        &mut self,
18526        stage: bool,
18527        ranges: Vec<Range<Anchor>>,
18528        cx: &mut Context<Self>,
18529    ) {
18530        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18531        cx.spawn(async move |this, cx| {
18532            task.await?;
18533            this.update(cx, |this, cx| {
18534                let snapshot = this.buffer.read(cx).snapshot(cx);
18535                let chunk_by = this
18536                    .diff_hunks_in_ranges(&ranges, &snapshot)
18537                    .chunk_by(|hunk| hunk.buffer_id);
18538                for (buffer_id, hunks) in &chunk_by {
18539                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18540                }
18541            })
18542        })
18543        .detach_and_log_err(cx);
18544    }
18545
18546    fn save_buffers_for_ranges_if_needed(
18547        &mut self,
18548        ranges: &[Range<Anchor>],
18549        cx: &mut Context<Editor>,
18550    ) -> Task<Result<()>> {
18551        let multibuffer = self.buffer.read(cx);
18552        let snapshot = multibuffer.read(cx);
18553        let buffer_ids: HashSet<_> = ranges
18554            .iter()
18555            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18556            .collect();
18557        drop(snapshot);
18558
18559        let mut buffers = HashSet::default();
18560        for buffer_id in buffer_ids {
18561            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18562                let buffer = buffer_entity.read(cx);
18563                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18564                {
18565                    buffers.insert(buffer_entity);
18566                }
18567            }
18568        }
18569
18570        if let Some(project) = &self.project {
18571            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18572        } else {
18573            Task::ready(Ok(()))
18574        }
18575    }
18576
18577    fn do_stage_or_unstage_and_next(
18578        &mut self,
18579        stage: bool,
18580        window: &mut Window,
18581        cx: &mut Context<Self>,
18582    ) {
18583        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18584
18585        if ranges.iter().any(|range| range.start != range.end) {
18586            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18587            return;
18588        }
18589
18590        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18591        let snapshot = self.snapshot(window, cx);
18592        let position = self.selections.newest::<Point>(cx).head();
18593        let mut row = snapshot
18594            .buffer_snapshot
18595            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18596            .find(|hunk| hunk.row_range.start.0 > position.row)
18597            .map(|hunk| hunk.row_range.start);
18598
18599        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18600        // Outside of the project diff editor, wrap around to the beginning.
18601        if !all_diff_hunks_expanded {
18602            row = row.or_else(|| {
18603                snapshot
18604                    .buffer_snapshot
18605                    .diff_hunks_in_range(Point::zero()..position)
18606                    .find(|hunk| hunk.row_range.end.0 < position.row)
18607                    .map(|hunk| hunk.row_range.start)
18608            });
18609        }
18610
18611        if let Some(row) = row {
18612            let destination = Point::new(row.0, 0);
18613            let autoscroll = Autoscroll::center();
18614
18615            self.unfold_ranges(&[destination..destination], false, false, cx);
18616            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18617                s.select_ranges([destination..destination]);
18618            });
18619        }
18620    }
18621
18622    fn do_stage_or_unstage(
18623        &self,
18624        stage: bool,
18625        buffer_id: BufferId,
18626        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18627        cx: &mut App,
18628    ) -> Option<()> {
18629        let project = self.project()?;
18630        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18631        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18632        let buffer_snapshot = buffer.read(cx).snapshot();
18633        let file_exists = buffer_snapshot
18634            .file()
18635            .is_some_and(|file| file.disk_state().exists());
18636        diff.update(cx, |diff, cx| {
18637            diff.stage_or_unstage_hunks(
18638                stage,
18639                &hunks
18640                    .map(|hunk| buffer_diff::DiffHunk {
18641                        buffer_range: hunk.buffer_range,
18642                        diff_base_byte_range: hunk.diff_base_byte_range,
18643                        secondary_status: hunk.secondary_status,
18644                        range: Point::zero()..Point::zero(), // unused
18645                    })
18646                    .collect::<Vec<_>>(),
18647                &buffer_snapshot,
18648                file_exists,
18649                cx,
18650            )
18651        });
18652        None
18653    }
18654
18655    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18656        let ranges: Vec<_> = self
18657            .selections
18658            .disjoint_anchors()
18659            .iter()
18660            .map(|s| s.range())
18661            .collect();
18662        self.buffer
18663            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18664    }
18665
18666    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18667        self.buffer.update(cx, |buffer, cx| {
18668            let ranges = vec![Anchor::min()..Anchor::max()];
18669            if !buffer.all_diff_hunks_expanded()
18670                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18671            {
18672                buffer.collapse_diff_hunks(ranges, cx);
18673                true
18674            } else {
18675                false
18676            }
18677        })
18678    }
18679
18680    fn toggle_diff_hunks_in_ranges(
18681        &mut self,
18682        ranges: Vec<Range<Anchor>>,
18683        cx: &mut Context<Editor>,
18684    ) {
18685        self.buffer.update(cx, |buffer, cx| {
18686            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18687            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18688        })
18689    }
18690
18691    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18692        self.buffer.update(cx, |buffer, cx| {
18693            let snapshot = buffer.snapshot(cx);
18694            let excerpt_id = range.end.excerpt_id;
18695            let point_range = range.to_point(&snapshot);
18696            let expand = !buffer.single_hunk_is_expanded(range, cx);
18697            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18698        })
18699    }
18700
18701    pub(crate) fn apply_all_diff_hunks(
18702        &mut self,
18703        _: &ApplyAllDiffHunks,
18704        window: &mut Window,
18705        cx: &mut Context<Self>,
18706    ) {
18707        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18708
18709        let buffers = self.buffer.read(cx).all_buffers();
18710        for branch_buffer in buffers {
18711            branch_buffer.update(cx, |branch_buffer, cx| {
18712                branch_buffer.merge_into_base(Vec::new(), cx);
18713            });
18714        }
18715
18716        if let Some(project) = self.project.clone() {
18717            self.save(
18718                SaveOptions {
18719                    format: true,
18720                    autosave: false,
18721                },
18722                project,
18723                window,
18724                cx,
18725            )
18726            .detach_and_log_err(cx);
18727        }
18728    }
18729
18730    pub(crate) fn apply_selected_diff_hunks(
18731        &mut self,
18732        _: &ApplyDiffHunk,
18733        window: &mut Window,
18734        cx: &mut Context<Self>,
18735    ) {
18736        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18737        let snapshot = self.snapshot(window, cx);
18738        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18739        let mut ranges_by_buffer = HashMap::default();
18740        self.transact(window, cx, |editor, _window, cx| {
18741            for hunk in hunks {
18742                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18743                    ranges_by_buffer
18744                        .entry(buffer.clone())
18745                        .or_insert_with(Vec::new)
18746                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18747                }
18748            }
18749
18750            for (buffer, ranges) in ranges_by_buffer {
18751                buffer.update(cx, |buffer, cx| {
18752                    buffer.merge_into_base(ranges, cx);
18753                });
18754            }
18755        });
18756
18757        if let Some(project) = self.project.clone() {
18758            self.save(
18759                SaveOptions {
18760                    format: true,
18761                    autosave: false,
18762                },
18763                project,
18764                window,
18765                cx,
18766            )
18767            .detach_and_log_err(cx);
18768        }
18769    }
18770
18771    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18772        if hovered != self.gutter_hovered {
18773            self.gutter_hovered = hovered;
18774            cx.notify();
18775        }
18776    }
18777
18778    pub fn insert_blocks(
18779        &mut self,
18780        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18781        autoscroll: Option<Autoscroll>,
18782        cx: &mut Context<Self>,
18783    ) -> Vec<CustomBlockId> {
18784        let blocks = self
18785            .display_map
18786            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18787        if let Some(autoscroll) = autoscroll {
18788            self.request_autoscroll(autoscroll, cx);
18789        }
18790        cx.notify();
18791        blocks
18792    }
18793
18794    pub fn resize_blocks(
18795        &mut self,
18796        heights: HashMap<CustomBlockId, u32>,
18797        autoscroll: Option<Autoscroll>,
18798        cx: &mut Context<Self>,
18799    ) {
18800        self.display_map
18801            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18802        if let Some(autoscroll) = autoscroll {
18803            self.request_autoscroll(autoscroll, cx);
18804        }
18805        cx.notify();
18806    }
18807
18808    pub fn replace_blocks(
18809        &mut self,
18810        renderers: HashMap<CustomBlockId, RenderBlock>,
18811        autoscroll: Option<Autoscroll>,
18812        cx: &mut Context<Self>,
18813    ) {
18814        self.display_map
18815            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18816        if let Some(autoscroll) = autoscroll {
18817            self.request_autoscroll(autoscroll, cx);
18818        }
18819        cx.notify();
18820    }
18821
18822    pub fn remove_blocks(
18823        &mut self,
18824        block_ids: HashSet<CustomBlockId>,
18825        autoscroll: Option<Autoscroll>,
18826        cx: &mut Context<Self>,
18827    ) {
18828        self.display_map.update(cx, |display_map, cx| {
18829            display_map.remove_blocks(block_ids, cx)
18830        });
18831        if let Some(autoscroll) = autoscroll {
18832            self.request_autoscroll(autoscroll, cx);
18833        }
18834        cx.notify();
18835    }
18836
18837    pub fn row_for_block(
18838        &self,
18839        block_id: CustomBlockId,
18840        cx: &mut Context<Self>,
18841    ) -> Option<DisplayRow> {
18842        self.display_map
18843            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18844    }
18845
18846    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18847        self.focused_block = Some(focused_block);
18848    }
18849
18850    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18851        self.focused_block.take()
18852    }
18853
18854    pub fn insert_creases(
18855        &mut self,
18856        creases: impl IntoIterator<Item = Crease<Anchor>>,
18857        cx: &mut Context<Self>,
18858    ) -> Vec<CreaseId> {
18859        self.display_map
18860            .update(cx, |map, cx| map.insert_creases(creases, cx))
18861    }
18862
18863    pub fn remove_creases(
18864        &mut self,
18865        ids: impl IntoIterator<Item = CreaseId>,
18866        cx: &mut Context<Self>,
18867    ) -> Vec<(CreaseId, Range<Anchor>)> {
18868        self.display_map
18869            .update(cx, |map, cx| map.remove_creases(ids, cx))
18870    }
18871
18872    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18873        self.display_map
18874            .update(cx, |map, cx| map.snapshot(cx))
18875            .longest_row()
18876    }
18877
18878    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18879        self.display_map
18880            .update(cx, |map, cx| map.snapshot(cx))
18881            .max_point()
18882    }
18883
18884    pub fn text(&self, cx: &App) -> String {
18885        self.buffer.read(cx).read(cx).text()
18886    }
18887
18888    pub fn is_empty(&self, cx: &App) -> bool {
18889        self.buffer.read(cx).read(cx).is_empty()
18890    }
18891
18892    pub fn text_option(&self, cx: &App) -> Option<String> {
18893        let text = self.text(cx);
18894        let text = text.trim();
18895
18896        if text.is_empty() {
18897            return None;
18898        }
18899
18900        Some(text.to_string())
18901    }
18902
18903    pub fn set_text(
18904        &mut self,
18905        text: impl Into<Arc<str>>,
18906        window: &mut Window,
18907        cx: &mut Context<Self>,
18908    ) {
18909        self.transact(window, cx, |this, _, cx| {
18910            this.buffer
18911                .read(cx)
18912                .as_singleton()
18913                .expect("you can only call set_text on editors for singleton buffers")
18914                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18915        });
18916    }
18917
18918    pub fn display_text(&self, cx: &mut App) -> String {
18919        self.display_map
18920            .update(cx, |map, cx| map.snapshot(cx))
18921            .text()
18922    }
18923
18924    fn create_minimap(
18925        &self,
18926        minimap_settings: MinimapSettings,
18927        window: &mut Window,
18928        cx: &mut Context<Self>,
18929    ) -> Option<Entity<Self>> {
18930        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18931            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18932    }
18933
18934    fn initialize_new_minimap(
18935        &self,
18936        minimap_settings: MinimapSettings,
18937        window: &mut Window,
18938        cx: &mut Context<Self>,
18939    ) -> Entity<Self> {
18940        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18941
18942        let mut minimap = Editor::new_internal(
18943            EditorMode::Minimap {
18944                parent: cx.weak_entity(),
18945            },
18946            self.buffer.clone(),
18947            None,
18948            Some(self.display_map.clone()),
18949            window,
18950            cx,
18951        );
18952        minimap.scroll_manager.clone_state(&self.scroll_manager);
18953        minimap.set_text_style_refinement(TextStyleRefinement {
18954            font_size: Some(MINIMAP_FONT_SIZE),
18955            font_weight: Some(MINIMAP_FONT_WEIGHT),
18956            ..Default::default()
18957        });
18958        minimap.update_minimap_configuration(minimap_settings, cx);
18959        cx.new(|_| minimap)
18960    }
18961
18962    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18963        let current_line_highlight = minimap_settings
18964            .current_line_highlight
18965            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18966        self.set_current_line_highlight(Some(current_line_highlight));
18967    }
18968
18969    pub fn minimap(&self) -> Option<&Entity<Self>> {
18970        self.minimap
18971            .as_ref()
18972            .filter(|_| self.minimap_visibility.visible())
18973    }
18974
18975    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18976        let mut wrap_guides = smallvec![];
18977
18978        if self.show_wrap_guides == Some(false) {
18979            return wrap_guides;
18980        }
18981
18982        let settings = self.buffer.read(cx).language_settings(cx);
18983        if settings.show_wrap_guides {
18984            match self.soft_wrap_mode(cx) {
18985                SoftWrap::Column(soft_wrap) => {
18986                    wrap_guides.push((soft_wrap as usize, true));
18987                }
18988                SoftWrap::Bounded(soft_wrap) => {
18989                    wrap_guides.push((soft_wrap as usize, true));
18990                }
18991                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18992            }
18993            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18994        }
18995
18996        wrap_guides
18997    }
18998
18999    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19000        let settings = self.buffer.read(cx).language_settings(cx);
19001        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19002        match mode {
19003            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19004                SoftWrap::None
19005            }
19006            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19007            language_settings::SoftWrap::PreferredLineLength => {
19008                SoftWrap::Column(settings.preferred_line_length)
19009            }
19010            language_settings::SoftWrap::Bounded => {
19011                SoftWrap::Bounded(settings.preferred_line_length)
19012            }
19013        }
19014    }
19015
19016    pub fn set_soft_wrap_mode(
19017        &mut self,
19018        mode: language_settings::SoftWrap,
19019
19020        cx: &mut Context<Self>,
19021    ) {
19022        self.soft_wrap_mode_override = Some(mode);
19023        cx.notify();
19024    }
19025
19026    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19027        self.hard_wrap = hard_wrap;
19028        cx.notify();
19029    }
19030
19031    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19032        self.text_style_refinement = Some(style);
19033    }
19034
19035    /// called by the Element so we know what style we were most recently rendered with.
19036    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19037        // We intentionally do not inform the display map about the minimap style
19038        // so that wrapping is not recalculated and stays consistent for the editor
19039        // and its linked minimap.
19040        if !self.mode.is_minimap() {
19041            let font = style.text.font();
19042            let font_size = style.text.font_size.to_pixels(window.rem_size());
19043            let display_map = self
19044                .placeholder_display_map
19045                .as_ref()
19046                .filter(|_| self.is_empty(cx))
19047                .unwrap_or(&self.display_map);
19048
19049            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19050        }
19051        self.style = Some(style);
19052    }
19053
19054    pub fn style(&self) -> Option<&EditorStyle> {
19055        self.style.as_ref()
19056    }
19057
19058    // Called by the element. This method is not designed to be called outside of the editor
19059    // element's layout code because it does not notify when rewrapping is computed synchronously.
19060    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19061        if self.is_empty(cx) {
19062            self.placeholder_display_map
19063                .as_ref()
19064                .map_or(false, |display_map| {
19065                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19066                })
19067        } else {
19068            self.display_map
19069                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19070        }
19071    }
19072
19073    pub fn set_soft_wrap(&mut self) {
19074        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19075    }
19076
19077    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19078        if self.soft_wrap_mode_override.is_some() {
19079            self.soft_wrap_mode_override.take();
19080        } else {
19081            let soft_wrap = match self.soft_wrap_mode(cx) {
19082                SoftWrap::GitDiff => return,
19083                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19084                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19085                    language_settings::SoftWrap::None
19086                }
19087            };
19088            self.soft_wrap_mode_override = Some(soft_wrap);
19089        }
19090        cx.notify();
19091    }
19092
19093    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19094        let Some(workspace) = self.workspace() else {
19095            return;
19096        };
19097        let fs = workspace.read(cx).app_state().fs.clone();
19098        let current_show = TabBarSettings::get_global(cx).show;
19099        update_settings_file(fs, cx, move |setting, _| {
19100            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19101        });
19102    }
19103
19104    pub fn toggle_indent_guides(
19105        &mut self,
19106        _: &ToggleIndentGuides,
19107        _: &mut Window,
19108        cx: &mut Context<Self>,
19109    ) {
19110        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19111            self.buffer
19112                .read(cx)
19113                .language_settings(cx)
19114                .indent_guides
19115                .enabled
19116        });
19117        self.show_indent_guides = Some(!currently_enabled);
19118        cx.notify();
19119    }
19120
19121    fn should_show_indent_guides(&self) -> Option<bool> {
19122        self.show_indent_guides
19123    }
19124
19125    pub fn toggle_line_numbers(
19126        &mut self,
19127        _: &ToggleLineNumbers,
19128        _: &mut Window,
19129        cx: &mut Context<Self>,
19130    ) {
19131        let mut editor_settings = EditorSettings::get_global(cx).clone();
19132        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19133        EditorSettings::override_global(editor_settings, cx);
19134    }
19135
19136    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19137        if let Some(show_line_numbers) = self.show_line_numbers {
19138            return show_line_numbers;
19139        }
19140        EditorSettings::get_global(cx).gutter.line_numbers
19141    }
19142
19143    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19144        self.use_relative_line_numbers
19145            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19146    }
19147
19148    pub fn toggle_relative_line_numbers(
19149        &mut self,
19150        _: &ToggleRelativeLineNumbers,
19151        _: &mut Window,
19152        cx: &mut Context<Self>,
19153    ) {
19154        let is_relative = self.should_use_relative_line_numbers(cx);
19155        self.set_relative_line_number(Some(!is_relative), cx)
19156    }
19157
19158    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19159        self.use_relative_line_numbers = is_relative;
19160        cx.notify();
19161    }
19162
19163    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19164        self.show_gutter = show_gutter;
19165        cx.notify();
19166    }
19167
19168    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19169        self.show_scrollbars = ScrollbarAxes {
19170            horizontal: show,
19171            vertical: show,
19172        };
19173        cx.notify();
19174    }
19175
19176    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19177        self.show_scrollbars.vertical = show;
19178        cx.notify();
19179    }
19180
19181    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19182        self.show_scrollbars.horizontal = show;
19183        cx.notify();
19184    }
19185
19186    pub fn set_minimap_visibility(
19187        &mut self,
19188        minimap_visibility: MinimapVisibility,
19189        window: &mut Window,
19190        cx: &mut Context<Self>,
19191    ) {
19192        if self.minimap_visibility != minimap_visibility {
19193            if minimap_visibility.visible() && self.minimap.is_none() {
19194                let minimap_settings = EditorSettings::get_global(cx).minimap;
19195                self.minimap =
19196                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19197            }
19198            self.minimap_visibility = minimap_visibility;
19199            cx.notify();
19200        }
19201    }
19202
19203    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19204        self.set_show_scrollbars(false, cx);
19205        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19206    }
19207
19208    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19209        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19210    }
19211
19212    /// Normally the text in full mode and auto height editors is padded on the
19213    /// left side by roughly half a character width for improved hit testing.
19214    ///
19215    /// Use this method to disable this for cases where this is not wanted (e.g.
19216    /// if you want to align the editor text with some other text above or below)
19217    /// or if you want to add this padding to single-line editors.
19218    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19219        self.offset_content = offset_content;
19220        cx.notify();
19221    }
19222
19223    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19224        self.show_line_numbers = Some(show_line_numbers);
19225        cx.notify();
19226    }
19227
19228    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19229        self.disable_expand_excerpt_buttons = true;
19230        cx.notify();
19231    }
19232
19233    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19234        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19235        cx.notify();
19236    }
19237
19238    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19239        self.show_code_actions = Some(show_code_actions);
19240        cx.notify();
19241    }
19242
19243    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19244        self.show_runnables = Some(show_runnables);
19245        cx.notify();
19246    }
19247
19248    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19249        self.show_breakpoints = Some(show_breakpoints);
19250        cx.notify();
19251    }
19252
19253    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19254        if self.display_map.read(cx).masked != masked {
19255            self.display_map.update(cx, |map, _| map.masked = masked);
19256        }
19257        cx.notify()
19258    }
19259
19260    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19261        self.show_wrap_guides = Some(show_wrap_guides);
19262        cx.notify();
19263    }
19264
19265    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19266        self.show_indent_guides = Some(show_indent_guides);
19267        cx.notify();
19268    }
19269
19270    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19271        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19272            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19273                && let Some(dir) = file.abs_path(cx).parent()
19274            {
19275                return Some(dir.to_owned());
19276            }
19277        }
19278
19279        None
19280    }
19281
19282    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19283        self.active_excerpt(cx)?
19284            .1
19285            .read(cx)
19286            .file()
19287            .and_then(|f| f.as_local())
19288    }
19289
19290    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19291        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19292            let buffer = buffer.read(cx);
19293            if let Some(project_path) = buffer.project_path(cx) {
19294                let project = self.project()?.read(cx);
19295                project.absolute_path(&project_path, cx)
19296            } else {
19297                buffer
19298                    .file()
19299                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19300            }
19301        })
19302    }
19303
19304    pub fn reveal_in_finder(
19305        &mut self,
19306        _: &RevealInFileManager,
19307        _window: &mut Window,
19308        cx: &mut Context<Self>,
19309    ) {
19310        if let Some(target) = self.target_file(cx) {
19311            cx.reveal_path(&target.abs_path(cx));
19312        }
19313    }
19314
19315    pub fn copy_path(
19316        &mut self,
19317        _: &zed_actions::workspace::CopyPath,
19318        _window: &mut Window,
19319        cx: &mut Context<Self>,
19320    ) {
19321        if let Some(path) = self.target_file_abs_path(cx)
19322            && let Some(path) = path.to_str()
19323        {
19324            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19325        } else {
19326            cx.propagate();
19327        }
19328    }
19329
19330    pub fn copy_relative_path(
19331        &mut self,
19332        _: &zed_actions::workspace::CopyRelativePath,
19333        _window: &mut Window,
19334        cx: &mut Context<Self>,
19335    ) {
19336        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19337            let project = self.project()?.read(cx);
19338            let path = buffer.read(cx).file()?.path();
19339            let path = path.display(project.path_style(cx));
19340            Some(path)
19341        }) {
19342            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19343        } else {
19344            cx.propagate();
19345        }
19346    }
19347
19348    /// Returns the project path for the editor's buffer, if any buffer is
19349    /// opened in the editor.
19350    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19351        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19352            buffer.read(cx).project_path(cx)
19353        } else {
19354            None
19355        }
19356    }
19357
19358    // Returns true if the editor handled a go-to-line request
19359    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19360        maybe!({
19361            let breakpoint_store = self.breakpoint_store.as_ref()?;
19362
19363            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19364            else {
19365                self.clear_row_highlights::<ActiveDebugLine>();
19366                return None;
19367            };
19368
19369            let position = active_stack_frame.position;
19370            let buffer_id = position.buffer_id?;
19371            let snapshot = self
19372                .project
19373                .as_ref()?
19374                .read(cx)
19375                .buffer_for_id(buffer_id, cx)?
19376                .read(cx)
19377                .snapshot();
19378
19379            let mut handled = false;
19380            for (id, ExcerptRange { context, .. }) in
19381                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19382            {
19383                if context.start.cmp(&position, &snapshot).is_ge()
19384                    || context.end.cmp(&position, &snapshot).is_lt()
19385                {
19386                    continue;
19387                }
19388                let snapshot = self.buffer.read(cx).snapshot(cx);
19389                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19390
19391                handled = true;
19392                self.clear_row_highlights::<ActiveDebugLine>();
19393
19394                self.go_to_line::<ActiveDebugLine>(
19395                    multibuffer_anchor,
19396                    Some(cx.theme().colors().editor_debugger_active_line_background),
19397                    window,
19398                    cx,
19399                );
19400
19401                cx.notify();
19402            }
19403
19404            handled.then_some(())
19405        })
19406        .is_some()
19407    }
19408
19409    pub fn copy_file_name_without_extension(
19410        &mut self,
19411        _: &CopyFileNameWithoutExtension,
19412        _: &mut Window,
19413        cx: &mut Context<Self>,
19414    ) {
19415        if let Some(file) = self.target_file(cx)
19416            && let Some(file_stem) = file.path().file_stem()
19417        {
19418            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19419        }
19420    }
19421
19422    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19423        if let Some(file) = self.target_file(cx)
19424            && let Some(name) = file.path().file_name()
19425        {
19426            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19427        }
19428    }
19429
19430    pub fn toggle_git_blame(
19431        &mut self,
19432        _: &::git::Blame,
19433        window: &mut Window,
19434        cx: &mut Context<Self>,
19435    ) {
19436        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19437
19438        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19439            self.start_git_blame(true, window, cx);
19440        }
19441
19442        cx.notify();
19443    }
19444
19445    pub fn toggle_git_blame_inline(
19446        &mut self,
19447        _: &ToggleGitBlameInline,
19448        window: &mut Window,
19449        cx: &mut Context<Self>,
19450    ) {
19451        self.toggle_git_blame_inline_internal(true, window, cx);
19452        cx.notify();
19453    }
19454
19455    pub fn open_git_blame_commit(
19456        &mut self,
19457        _: &OpenGitBlameCommit,
19458        window: &mut Window,
19459        cx: &mut Context<Self>,
19460    ) {
19461        self.open_git_blame_commit_internal(window, cx);
19462    }
19463
19464    fn open_git_blame_commit_internal(
19465        &mut self,
19466        window: &mut Window,
19467        cx: &mut Context<Self>,
19468    ) -> Option<()> {
19469        let blame = self.blame.as_ref()?;
19470        let snapshot = self.snapshot(window, cx);
19471        let cursor = self.selections.newest::<Point>(cx).head();
19472        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19473        let (_, blame_entry) = blame
19474            .update(cx, |blame, cx| {
19475                blame
19476                    .blame_for_rows(
19477                        &[RowInfo {
19478                            buffer_id: Some(buffer.remote_id()),
19479                            buffer_row: Some(point.row),
19480                            ..Default::default()
19481                        }],
19482                        cx,
19483                    )
19484                    .next()
19485            })
19486            .flatten()?;
19487        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19488        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19489        let workspace = self.workspace()?.downgrade();
19490        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19491        None
19492    }
19493
19494    pub fn git_blame_inline_enabled(&self) -> bool {
19495        self.git_blame_inline_enabled
19496    }
19497
19498    pub fn toggle_selection_menu(
19499        &mut self,
19500        _: &ToggleSelectionMenu,
19501        _: &mut Window,
19502        cx: &mut Context<Self>,
19503    ) {
19504        self.show_selection_menu = self
19505            .show_selection_menu
19506            .map(|show_selections_menu| !show_selections_menu)
19507            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19508
19509        cx.notify();
19510    }
19511
19512    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19513        self.show_selection_menu
19514            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19515    }
19516
19517    fn start_git_blame(
19518        &mut self,
19519        user_triggered: bool,
19520        window: &mut Window,
19521        cx: &mut Context<Self>,
19522    ) {
19523        if let Some(project) = self.project() {
19524            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19525                && buffer.read(cx).file().is_none()
19526            {
19527                return;
19528            }
19529
19530            let focused = self.focus_handle(cx).contains_focused(window, cx);
19531
19532            let project = project.clone();
19533            let blame = cx
19534                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19535            self.blame_subscription =
19536                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19537            self.blame = Some(blame);
19538        }
19539    }
19540
19541    fn toggle_git_blame_inline_internal(
19542        &mut self,
19543        user_triggered: bool,
19544        window: &mut Window,
19545        cx: &mut Context<Self>,
19546    ) {
19547        if self.git_blame_inline_enabled {
19548            self.git_blame_inline_enabled = false;
19549            self.show_git_blame_inline = false;
19550            self.show_git_blame_inline_delay_task.take();
19551        } else {
19552            self.git_blame_inline_enabled = true;
19553            self.start_git_blame_inline(user_triggered, window, cx);
19554        }
19555
19556        cx.notify();
19557    }
19558
19559    fn start_git_blame_inline(
19560        &mut self,
19561        user_triggered: bool,
19562        window: &mut Window,
19563        cx: &mut Context<Self>,
19564    ) {
19565        self.start_git_blame(user_triggered, window, cx);
19566
19567        if ProjectSettings::get_global(cx)
19568            .git
19569            .inline_blame_delay()
19570            .is_some()
19571        {
19572            self.start_inline_blame_timer(window, cx);
19573        } else {
19574            self.show_git_blame_inline = true
19575        }
19576    }
19577
19578    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19579        self.blame.as_ref()
19580    }
19581
19582    pub fn show_git_blame_gutter(&self) -> bool {
19583        self.show_git_blame_gutter
19584    }
19585
19586    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19587        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19588    }
19589
19590    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19591        self.show_git_blame_inline
19592            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19593            && !self.newest_selection_head_on_empty_line(cx)
19594            && self.has_blame_entries(cx)
19595    }
19596
19597    fn has_blame_entries(&self, cx: &App) -> bool {
19598        self.blame()
19599            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19600    }
19601
19602    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19603        let cursor_anchor = self.selections.newest_anchor().head();
19604
19605        let snapshot = self.buffer.read(cx).snapshot(cx);
19606        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19607
19608        snapshot.line_len(buffer_row) == 0
19609    }
19610
19611    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19612        let buffer_and_selection = maybe!({
19613            let selection = self.selections.newest::<Point>(cx);
19614            let selection_range = selection.range();
19615
19616            let multi_buffer = self.buffer().read(cx);
19617            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19618            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19619
19620            let (buffer, range, _) = if selection.reversed {
19621                buffer_ranges.first()
19622            } else {
19623                buffer_ranges.last()
19624            }?;
19625
19626            let selection = text::ToPoint::to_point(&range.start, buffer).row
19627                ..text::ToPoint::to_point(&range.end, buffer).row;
19628            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19629        });
19630
19631        let Some((buffer, selection)) = buffer_and_selection else {
19632            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19633        };
19634
19635        let Some(project) = self.project() else {
19636            return Task::ready(Err(anyhow!("editor does not have project")));
19637        };
19638
19639        project.update(cx, |project, cx| {
19640            project.get_permalink_to_line(&buffer, selection, cx)
19641        })
19642    }
19643
19644    pub fn copy_permalink_to_line(
19645        &mut self,
19646        _: &CopyPermalinkToLine,
19647        window: &mut Window,
19648        cx: &mut Context<Self>,
19649    ) {
19650        let permalink_task = self.get_permalink_to_line(cx);
19651        let workspace = self.workspace();
19652
19653        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19654            Ok(permalink) => {
19655                cx.update(|_, cx| {
19656                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19657                })
19658                .ok();
19659            }
19660            Err(err) => {
19661                let message = format!("Failed to copy permalink: {err}");
19662
19663                anyhow::Result::<()>::Err(err).log_err();
19664
19665                if let Some(workspace) = workspace {
19666                    workspace
19667                        .update_in(cx, |workspace, _, cx| {
19668                            struct CopyPermalinkToLine;
19669
19670                            workspace.show_toast(
19671                                Toast::new(
19672                                    NotificationId::unique::<CopyPermalinkToLine>(),
19673                                    message,
19674                                ),
19675                                cx,
19676                            )
19677                        })
19678                        .ok();
19679                }
19680            }
19681        })
19682        .detach();
19683    }
19684
19685    pub fn copy_file_location(
19686        &mut self,
19687        _: &CopyFileLocation,
19688        _: &mut Window,
19689        cx: &mut Context<Self>,
19690    ) {
19691        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19692        if let Some(file) = self.target_file(cx) {
19693            let path = file.path().display(file.path_style(cx));
19694            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19695        }
19696    }
19697
19698    pub fn open_permalink_to_line(
19699        &mut self,
19700        _: &OpenPermalinkToLine,
19701        window: &mut Window,
19702        cx: &mut Context<Self>,
19703    ) {
19704        let permalink_task = self.get_permalink_to_line(cx);
19705        let workspace = self.workspace();
19706
19707        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19708            Ok(permalink) => {
19709                cx.update(|_, cx| {
19710                    cx.open_url(permalink.as_ref());
19711                })
19712                .ok();
19713            }
19714            Err(err) => {
19715                let message = format!("Failed to open permalink: {err}");
19716
19717                anyhow::Result::<()>::Err(err).log_err();
19718
19719                if let Some(workspace) = workspace {
19720                    workspace
19721                        .update(cx, |workspace, cx| {
19722                            struct OpenPermalinkToLine;
19723
19724                            workspace.show_toast(
19725                                Toast::new(
19726                                    NotificationId::unique::<OpenPermalinkToLine>(),
19727                                    message,
19728                                ),
19729                                cx,
19730                            )
19731                        })
19732                        .ok();
19733                }
19734            }
19735        })
19736        .detach();
19737    }
19738
19739    pub fn insert_uuid_v4(
19740        &mut self,
19741        _: &InsertUuidV4,
19742        window: &mut Window,
19743        cx: &mut Context<Self>,
19744    ) {
19745        self.insert_uuid(UuidVersion::V4, window, cx);
19746    }
19747
19748    pub fn insert_uuid_v7(
19749        &mut self,
19750        _: &InsertUuidV7,
19751        window: &mut Window,
19752        cx: &mut Context<Self>,
19753    ) {
19754        self.insert_uuid(UuidVersion::V7, window, cx);
19755    }
19756
19757    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19758        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19759        self.transact(window, cx, |this, window, cx| {
19760            let edits = this
19761                .selections
19762                .all::<Point>(cx)
19763                .into_iter()
19764                .map(|selection| {
19765                    let uuid = match version {
19766                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19767                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19768                    };
19769
19770                    (selection.range(), uuid.to_string())
19771                });
19772            this.edit(edits, cx);
19773            this.refresh_edit_prediction(true, false, window, cx);
19774        });
19775    }
19776
19777    pub fn open_selections_in_multibuffer(
19778        &mut self,
19779        _: &OpenSelectionsInMultibuffer,
19780        window: &mut Window,
19781        cx: &mut Context<Self>,
19782    ) {
19783        let multibuffer = self.buffer.read(cx);
19784
19785        let Some(buffer) = multibuffer.as_singleton() else {
19786            return;
19787        };
19788
19789        let Some(workspace) = self.workspace() else {
19790            return;
19791        };
19792
19793        let title = multibuffer.title(cx).to_string();
19794
19795        let locations = self
19796            .selections
19797            .all_anchors(cx)
19798            .iter()
19799            .map(|selection| {
19800                (
19801                    buffer.clone(),
19802                    (selection.start.text_anchor..selection.end.text_anchor)
19803                        .to_point(buffer.read(cx)),
19804                )
19805            })
19806            .into_group_map();
19807
19808        cx.spawn_in(window, async move |_, cx| {
19809            workspace.update_in(cx, |workspace, window, cx| {
19810                Self::open_locations_in_multibuffer(
19811                    workspace,
19812                    locations,
19813                    format!("Selections for '{title}'"),
19814                    false,
19815                    MultibufferSelectionMode::All,
19816                    window,
19817                    cx,
19818                );
19819            })
19820        })
19821        .detach();
19822    }
19823
19824    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19825    /// last highlight added will be used.
19826    ///
19827    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19828    pub fn highlight_rows<T: 'static>(
19829        &mut self,
19830        range: Range<Anchor>,
19831        color: Hsla,
19832        options: RowHighlightOptions,
19833        cx: &mut Context<Self>,
19834    ) {
19835        let snapshot = self.buffer().read(cx).snapshot(cx);
19836        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19837        let ix = row_highlights.binary_search_by(|highlight| {
19838            Ordering::Equal
19839                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19840                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19841        });
19842
19843        if let Err(mut ix) = ix {
19844            let index = post_inc(&mut self.highlight_order);
19845
19846            // If this range intersects with the preceding highlight, then merge it with
19847            // the preceding highlight. Otherwise insert a new highlight.
19848            let mut merged = false;
19849            if ix > 0 {
19850                let prev_highlight = &mut row_highlights[ix - 1];
19851                if prev_highlight
19852                    .range
19853                    .end
19854                    .cmp(&range.start, &snapshot)
19855                    .is_ge()
19856                {
19857                    ix -= 1;
19858                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19859                        prev_highlight.range.end = range.end;
19860                    }
19861                    merged = true;
19862                    prev_highlight.index = index;
19863                    prev_highlight.color = color;
19864                    prev_highlight.options = options;
19865                }
19866            }
19867
19868            if !merged {
19869                row_highlights.insert(
19870                    ix,
19871                    RowHighlight {
19872                        range,
19873                        index,
19874                        color,
19875                        options,
19876                        type_id: TypeId::of::<T>(),
19877                    },
19878                );
19879            }
19880
19881            // If any of the following highlights intersect with this one, merge them.
19882            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19883                let highlight = &row_highlights[ix];
19884                if next_highlight
19885                    .range
19886                    .start
19887                    .cmp(&highlight.range.end, &snapshot)
19888                    .is_le()
19889                {
19890                    if next_highlight
19891                        .range
19892                        .end
19893                        .cmp(&highlight.range.end, &snapshot)
19894                        .is_gt()
19895                    {
19896                        row_highlights[ix].range.end = next_highlight.range.end;
19897                    }
19898                    row_highlights.remove(ix + 1);
19899                } else {
19900                    break;
19901                }
19902            }
19903        }
19904    }
19905
19906    /// Remove any highlighted row ranges of the given type that intersect the
19907    /// given ranges.
19908    pub fn remove_highlighted_rows<T: 'static>(
19909        &mut self,
19910        ranges_to_remove: Vec<Range<Anchor>>,
19911        cx: &mut Context<Self>,
19912    ) {
19913        let snapshot = self.buffer().read(cx).snapshot(cx);
19914        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19915        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19916        row_highlights.retain(|highlight| {
19917            while let Some(range_to_remove) = ranges_to_remove.peek() {
19918                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19919                    Ordering::Less | Ordering::Equal => {
19920                        ranges_to_remove.next();
19921                    }
19922                    Ordering::Greater => {
19923                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19924                            Ordering::Less | Ordering::Equal => {
19925                                return false;
19926                            }
19927                            Ordering::Greater => break,
19928                        }
19929                    }
19930                }
19931            }
19932
19933            true
19934        })
19935    }
19936
19937    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19938    pub fn clear_row_highlights<T: 'static>(&mut self) {
19939        self.highlighted_rows.remove(&TypeId::of::<T>());
19940    }
19941
19942    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19943    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19944        self.highlighted_rows
19945            .get(&TypeId::of::<T>())
19946            .map_or(&[] as &[_], |vec| vec.as_slice())
19947            .iter()
19948            .map(|highlight| (highlight.range.clone(), highlight.color))
19949    }
19950
19951    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19952    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19953    /// Allows to ignore certain kinds of highlights.
19954    pub fn highlighted_display_rows(
19955        &self,
19956        window: &mut Window,
19957        cx: &mut App,
19958    ) -> BTreeMap<DisplayRow, LineHighlight> {
19959        let snapshot = self.snapshot(window, cx);
19960        let mut used_highlight_orders = HashMap::default();
19961        self.highlighted_rows
19962            .iter()
19963            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19964            .fold(
19965                BTreeMap::<DisplayRow, LineHighlight>::new(),
19966                |mut unique_rows, highlight| {
19967                    let start = highlight.range.start.to_display_point(&snapshot);
19968                    let end = highlight.range.end.to_display_point(&snapshot);
19969                    let start_row = start.row().0;
19970                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19971                        && end.column() == 0
19972                    {
19973                        end.row().0.saturating_sub(1)
19974                    } else {
19975                        end.row().0
19976                    };
19977                    for row in start_row..=end_row {
19978                        let used_index =
19979                            used_highlight_orders.entry(row).or_insert(highlight.index);
19980                        if highlight.index >= *used_index {
19981                            *used_index = highlight.index;
19982                            unique_rows.insert(
19983                                DisplayRow(row),
19984                                LineHighlight {
19985                                    include_gutter: highlight.options.include_gutter,
19986                                    border: None,
19987                                    background: highlight.color.into(),
19988                                    type_id: Some(highlight.type_id),
19989                                },
19990                            );
19991                        }
19992                    }
19993                    unique_rows
19994                },
19995            )
19996    }
19997
19998    pub fn highlighted_display_row_for_autoscroll(
19999        &self,
20000        snapshot: &DisplaySnapshot,
20001    ) -> Option<DisplayRow> {
20002        self.highlighted_rows
20003            .values()
20004            .flat_map(|highlighted_rows| highlighted_rows.iter())
20005            .filter_map(|highlight| {
20006                if highlight.options.autoscroll {
20007                    Some(highlight.range.start.to_display_point(snapshot).row())
20008                } else {
20009                    None
20010                }
20011            })
20012            .min()
20013    }
20014
20015    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20016        self.highlight_background::<SearchWithinRange>(
20017            ranges,
20018            |colors| colors.colors().editor_document_highlight_read_background,
20019            cx,
20020        )
20021    }
20022
20023    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20024        self.breadcrumb_header = Some(new_header);
20025    }
20026
20027    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20028        self.clear_background_highlights::<SearchWithinRange>(cx);
20029    }
20030
20031    pub fn highlight_background<T: 'static>(
20032        &mut self,
20033        ranges: &[Range<Anchor>],
20034        color_fetcher: fn(&Theme) -> Hsla,
20035        cx: &mut Context<Self>,
20036    ) {
20037        self.background_highlights.insert(
20038            HighlightKey::Type(TypeId::of::<T>()),
20039            (color_fetcher, Arc::from(ranges)),
20040        );
20041        self.scrollbar_marker_state.dirty = true;
20042        cx.notify();
20043    }
20044
20045    pub fn highlight_background_key<T: 'static>(
20046        &mut self,
20047        key: usize,
20048        ranges: &[Range<Anchor>],
20049        color_fetcher: fn(&Theme) -> Hsla,
20050        cx: &mut Context<Self>,
20051    ) {
20052        self.background_highlights.insert(
20053            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20054            (color_fetcher, Arc::from(ranges)),
20055        );
20056        self.scrollbar_marker_state.dirty = true;
20057        cx.notify();
20058    }
20059
20060    pub fn clear_background_highlights<T: 'static>(
20061        &mut self,
20062        cx: &mut Context<Self>,
20063    ) -> Option<BackgroundHighlight> {
20064        let text_highlights = self
20065            .background_highlights
20066            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20067        if !text_highlights.1.is_empty() {
20068            self.scrollbar_marker_state.dirty = true;
20069            cx.notify();
20070        }
20071        Some(text_highlights)
20072    }
20073
20074    pub fn highlight_gutter<T: 'static>(
20075        &mut self,
20076        ranges: impl Into<Vec<Range<Anchor>>>,
20077        color_fetcher: fn(&App) -> Hsla,
20078        cx: &mut Context<Self>,
20079    ) {
20080        self.gutter_highlights
20081            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20082        cx.notify();
20083    }
20084
20085    pub fn clear_gutter_highlights<T: 'static>(
20086        &mut self,
20087        cx: &mut Context<Self>,
20088    ) -> Option<GutterHighlight> {
20089        cx.notify();
20090        self.gutter_highlights.remove(&TypeId::of::<T>())
20091    }
20092
20093    pub fn insert_gutter_highlight<T: 'static>(
20094        &mut self,
20095        range: Range<Anchor>,
20096        color_fetcher: fn(&App) -> Hsla,
20097        cx: &mut Context<Self>,
20098    ) {
20099        let snapshot = self.buffer().read(cx).snapshot(cx);
20100        let mut highlights = self
20101            .gutter_highlights
20102            .remove(&TypeId::of::<T>())
20103            .map(|(_, highlights)| highlights)
20104            .unwrap_or_default();
20105        let ix = highlights.binary_search_by(|highlight| {
20106            Ordering::Equal
20107                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20108                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20109        });
20110        if let Err(ix) = ix {
20111            highlights.insert(ix, range);
20112        }
20113        self.gutter_highlights
20114            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20115    }
20116
20117    pub fn remove_gutter_highlights<T: 'static>(
20118        &mut self,
20119        ranges_to_remove: Vec<Range<Anchor>>,
20120        cx: &mut Context<Self>,
20121    ) {
20122        let snapshot = self.buffer().read(cx).snapshot(cx);
20123        let Some((color_fetcher, mut gutter_highlights)) =
20124            self.gutter_highlights.remove(&TypeId::of::<T>())
20125        else {
20126            return;
20127        };
20128        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20129        gutter_highlights.retain(|highlight| {
20130            while let Some(range_to_remove) = ranges_to_remove.peek() {
20131                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20132                    Ordering::Less | Ordering::Equal => {
20133                        ranges_to_remove.next();
20134                    }
20135                    Ordering::Greater => {
20136                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20137                            Ordering::Less | Ordering::Equal => {
20138                                return false;
20139                            }
20140                            Ordering::Greater => break,
20141                        }
20142                    }
20143                }
20144            }
20145
20146            true
20147        });
20148        self.gutter_highlights
20149            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20150    }
20151
20152    #[cfg(feature = "test-support")]
20153    pub fn all_text_highlights(
20154        &self,
20155        window: &mut Window,
20156        cx: &mut Context<Self>,
20157    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20158        let snapshot = self.snapshot(window, cx);
20159        self.display_map.update(cx, |display_map, _| {
20160            display_map
20161                .all_text_highlights()
20162                .map(|highlight| {
20163                    let (style, ranges) = highlight.as_ref();
20164                    (
20165                        *style,
20166                        ranges
20167                            .iter()
20168                            .map(|range| range.clone().to_display_points(&snapshot))
20169                            .collect(),
20170                    )
20171                })
20172                .collect()
20173        })
20174    }
20175
20176    #[cfg(feature = "test-support")]
20177    pub fn all_text_background_highlights(
20178        &self,
20179        window: &mut Window,
20180        cx: &mut Context<Self>,
20181    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20182        let snapshot = self.snapshot(window, cx);
20183        let buffer = &snapshot.buffer_snapshot;
20184        let start = buffer.anchor_before(0);
20185        let end = buffer.anchor_after(buffer.len());
20186        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20187    }
20188
20189    #[cfg(any(test, feature = "test-support"))]
20190    pub fn sorted_background_highlights_in_range(
20191        &self,
20192        search_range: Range<Anchor>,
20193        display_snapshot: &DisplaySnapshot,
20194        theme: &Theme,
20195    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20196        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20197        res.sort_by(|a, b| {
20198            a.0.start
20199                .cmp(&b.0.start)
20200                .then_with(|| a.0.end.cmp(&b.0.end))
20201                .then_with(|| a.1.cmp(&b.1))
20202        });
20203        res
20204    }
20205
20206    #[cfg(feature = "test-support")]
20207    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20208        let snapshot = self.buffer().read(cx).snapshot(cx);
20209
20210        let highlights = self
20211            .background_highlights
20212            .get(&HighlightKey::Type(TypeId::of::<
20213                items::BufferSearchHighlights,
20214            >()));
20215
20216        if let Some((_color, ranges)) = highlights {
20217            ranges
20218                .iter()
20219                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20220                .collect_vec()
20221        } else {
20222            vec![]
20223        }
20224    }
20225
20226    fn document_highlights_for_position<'a>(
20227        &'a self,
20228        position: Anchor,
20229        buffer: &'a MultiBufferSnapshot,
20230    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20231        let read_highlights = self
20232            .background_highlights
20233            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20234            .map(|h| &h.1);
20235        let write_highlights = self
20236            .background_highlights
20237            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20238            .map(|h| &h.1);
20239        let left_position = position.bias_left(buffer);
20240        let right_position = position.bias_right(buffer);
20241        read_highlights
20242            .into_iter()
20243            .chain(write_highlights)
20244            .flat_map(move |ranges| {
20245                let start_ix = match ranges.binary_search_by(|probe| {
20246                    let cmp = probe.end.cmp(&left_position, buffer);
20247                    if cmp.is_ge() {
20248                        Ordering::Greater
20249                    } else {
20250                        Ordering::Less
20251                    }
20252                }) {
20253                    Ok(i) | Err(i) => i,
20254                };
20255
20256                ranges[start_ix..]
20257                    .iter()
20258                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20259            })
20260    }
20261
20262    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20263        self.background_highlights
20264            .get(&HighlightKey::Type(TypeId::of::<T>()))
20265            .is_some_and(|(_, highlights)| !highlights.is_empty())
20266    }
20267
20268    /// Returns all background highlights for a given range.
20269    ///
20270    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20271    pub fn background_highlights_in_range(
20272        &self,
20273        search_range: Range<Anchor>,
20274        display_snapshot: &DisplaySnapshot,
20275        theme: &Theme,
20276    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20277        let mut results = Vec::new();
20278        for (color_fetcher, ranges) in self.background_highlights.values() {
20279            let color = color_fetcher(theme);
20280            let start_ix = match ranges.binary_search_by(|probe| {
20281                let cmp = probe
20282                    .end
20283                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20284                if cmp.is_gt() {
20285                    Ordering::Greater
20286                } else {
20287                    Ordering::Less
20288                }
20289            }) {
20290                Ok(i) | Err(i) => i,
20291            };
20292            for range in &ranges[start_ix..] {
20293                if range
20294                    .start
20295                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20296                    .is_ge()
20297                {
20298                    break;
20299                }
20300
20301                let start = range.start.to_display_point(display_snapshot);
20302                let end = range.end.to_display_point(display_snapshot);
20303                results.push((start..end, color))
20304            }
20305        }
20306        results
20307    }
20308
20309    pub fn gutter_highlights_in_range(
20310        &self,
20311        search_range: Range<Anchor>,
20312        display_snapshot: &DisplaySnapshot,
20313        cx: &App,
20314    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20315        let mut results = Vec::new();
20316        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20317            let color = color_fetcher(cx);
20318            let start_ix = match ranges.binary_search_by(|probe| {
20319                let cmp = probe
20320                    .end
20321                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20322                if cmp.is_gt() {
20323                    Ordering::Greater
20324                } else {
20325                    Ordering::Less
20326                }
20327            }) {
20328                Ok(i) | Err(i) => i,
20329            };
20330            for range in &ranges[start_ix..] {
20331                if range
20332                    .start
20333                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20334                    .is_ge()
20335                {
20336                    break;
20337                }
20338
20339                let start = range.start.to_display_point(display_snapshot);
20340                let end = range.end.to_display_point(display_snapshot);
20341                results.push((start..end, color))
20342            }
20343        }
20344        results
20345    }
20346
20347    /// Get the text ranges corresponding to the redaction query
20348    pub fn redacted_ranges(
20349        &self,
20350        search_range: Range<Anchor>,
20351        display_snapshot: &DisplaySnapshot,
20352        cx: &App,
20353    ) -> Vec<Range<DisplayPoint>> {
20354        display_snapshot
20355            .buffer_snapshot
20356            .redacted_ranges(search_range, |file| {
20357                if let Some(file) = file {
20358                    file.is_private()
20359                        && EditorSettings::get(
20360                            Some(SettingsLocation {
20361                                worktree_id: file.worktree_id(cx),
20362                                path: file.path().as_ref(),
20363                            }),
20364                            cx,
20365                        )
20366                        .redact_private_values
20367                } else {
20368                    false
20369                }
20370            })
20371            .map(|range| {
20372                range.start.to_display_point(display_snapshot)
20373                    ..range.end.to_display_point(display_snapshot)
20374            })
20375            .collect()
20376    }
20377
20378    pub fn highlight_text_key<T: 'static>(
20379        &mut self,
20380        key: usize,
20381        ranges: Vec<Range<Anchor>>,
20382        style: HighlightStyle,
20383        cx: &mut Context<Self>,
20384    ) {
20385        self.display_map.update(cx, |map, _| {
20386            map.highlight_text(
20387                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20388                ranges,
20389                style,
20390            );
20391        });
20392        cx.notify();
20393    }
20394
20395    pub fn highlight_text<T: 'static>(
20396        &mut self,
20397        ranges: Vec<Range<Anchor>>,
20398        style: HighlightStyle,
20399        cx: &mut Context<Self>,
20400    ) {
20401        self.display_map.update(cx, |map, _| {
20402            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20403        });
20404        cx.notify();
20405    }
20406
20407    pub(crate) fn highlight_inlays<T: 'static>(
20408        &mut self,
20409        highlights: Vec<InlayHighlight>,
20410        style: HighlightStyle,
20411        cx: &mut Context<Self>,
20412    ) {
20413        self.display_map.update(cx, |map, _| {
20414            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20415        });
20416        cx.notify();
20417    }
20418
20419    pub fn text_highlights<'a, T: 'static>(
20420        &'a self,
20421        cx: &'a App,
20422    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20423        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20424    }
20425
20426    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20427        let cleared = self
20428            .display_map
20429            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20430        if cleared {
20431            cx.notify();
20432        }
20433    }
20434
20435    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20436        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20437            && self.focus_handle.is_focused(window)
20438    }
20439
20440    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20441        self.show_cursor_when_unfocused = is_enabled;
20442        cx.notify();
20443    }
20444
20445    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20446        cx.notify();
20447    }
20448
20449    fn on_debug_session_event(
20450        &mut self,
20451        _session: Entity<Session>,
20452        event: &SessionEvent,
20453        cx: &mut Context<Self>,
20454    ) {
20455        if let SessionEvent::InvalidateInlineValue = event {
20456            self.refresh_inline_values(cx);
20457        }
20458    }
20459
20460    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20461        let Some(project) = self.project.clone() else {
20462            return;
20463        };
20464
20465        if !self.inline_value_cache.enabled {
20466            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20467            self.splice_inlays(&inlays, Vec::new(), cx);
20468            return;
20469        }
20470
20471        let current_execution_position = self
20472            .highlighted_rows
20473            .get(&TypeId::of::<ActiveDebugLine>())
20474            .and_then(|lines| lines.last().map(|line| line.range.end));
20475
20476        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20477            let inline_values = editor
20478                .update(cx, |editor, cx| {
20479                    let Some(current_execution_position) = current_execution_position else {
20480                        return Some(Task::ready(Ok(Vec::new())));
20481                    };
20482
20483                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20484                        let snapshot = buffer.snapshot(cx);
20485
20486                        let excerpt = snapshot.excerpt_containing(
20487                            current_execution_position..current_execution_position,
20488                        )?;
20489
20490                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20491                    })?;
20492
20493                    let range =
20494                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20495
20496                    project.inline_values(buffer, range, cx)
20497                })
20498                .ok()
20499                .flatten()?
20500                .await
20501                .context("refreshing debugger inlays")
20502                .log_err()?;
20503
20504            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20505
20506            for (buffer_id, inline_value) in inline_values
20507                .into_iter()
20508                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20509            {
20510                buffer_inline_values
20511                    .entry(buffer_id)
20512                    .or_default()
20513                    .push(inline_value);
20514            }
20515
20516            editor
20517                .update(cx, |editor, cx| {
20518                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20519                    let mut new_inlays = Vec::default();
20520
20521                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20522                        let buffer_id = buffer_snapshot.remote_id();
20523                        buffer_inline_values
20524                            .get(&buffer_id)
20525                            .into_iter()
20526                            .flatten()
20527                            .for_each(|hint| {
20528                                let inlay = Inlay::debugger(
20529                                    post_inc(&mut editor.next_inlay_id),
20530                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20531                                    hint.text(),
20532                                );
20533                                if !inlay.text.chars().contains(&'\n') {
20534                                    new_inlays.push(inlay);
20535                                }
20536                            });
20537                    }
20538
20539                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20540                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20541
20542                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20543                })
20544                .ok()?;
20545            Some(())
20546        });
20547    }
20548
20549    fn on_buffer_event(
20550        &mut self,
20551        multibuffer: &Entity<MultiBuffer>,
20552        event: &multi_buffer::Event,
20553        window: &mut Window,
20554        cx: &mut Context<Self>,
20555    ) {
20556        match event {
20557            multi_buffer::Event::Edited {
20558                singleton_buffer_edited,
20559                edited_buffer,
20560            } => {
20561                self.scrollbar_marker_state.dirty = true;
20562                self.active_indent_guides_state.dirty = true;
20563                self.refresh_active_diagnostics(cx);
20564                self.refresh_code_actions(window, cx);
20565                self.refresh_selected_text_highlights(true, window, cx);
20566                self.refresh_single_line_folds(window, cx);
20567                refresh_matching_bracket_highlights(self, window, cx);
20568                if self.has_active_edit_prediction() {
20569                    self.update_visible_edit_prediction(window, cx);
20570                }
20571                if let Some(project) = self.project.as_ref()
20572                    && let Some(edited_buffer) = edited_buffer
20573                {
20574                    project.update(cx, |project, cx| {
20575                        self.registered_buffers
20576                            .entry(edited_buffer.read(cx).remote_id())
20577                            .or_insert_with(|| {
20578                                project.register_buffer_with_language_servers(edited_buffer, cx)
20579                            });
20580                    });
20581                }
20582                cx.emit(EditorEvent::BufferEdited);
20583                cx.emit(SearchEvent::MatchesInvalidated);
20584
20585                if let Some(buffer) = edited_buffer {
20586                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20587                }
20588
20589                if *singleton_buffer_edited {
20590                    if let Some(buffer) = edited_buffer
20591                        && buffer.read(cx).file().is_none()
20592                    {
20593                        cx.emit(EditorEvent::TitleChanged);
20594                    }
20595                    if let Some(project) = &self.project {
20596                        #[allow(clippy::mutable_key_type)]
20597                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20598                            multibuffer
20599                                .all_buffers()
20600                                .into_iter()
20601                                .filter_map(|buffer| {
20602                                    buffer.update(cx, |buffer, cx| {
20603                                        let language = buffer.language()?;
20604                                        let should_discard = project.update(cx, |project, cx| {
20605                                            project.is_local()
20606                                                && !project.has_language_servers_for(buffer, cx)
20607                                        });
20608                                        should_discard.not().then_some(language.clone())
20609                                    })
20610                                })
20611                                .collect::<HashSet<_>>()
20612                        });
20613                        if !languages_affected.is_empty() {
20614                            self.refresh_inlay_hints(
20615                                InlayHintRefreshReason::BufferEdited(languages_affected),
20616                                cx,
20617                            );
20618                        }
20619                    }
20620                }
20621
20622                let Some(project) = &self.project else { return };
20623                let (telemetry, is_via_ssh) = {
20624                    let project = project.read(cx);
20625                    let telemetry = project.client().telemetry().clone();
20626                    let is_via_ssh = project.is_via_remote_server();
20627                    (telemetry, is_via_ssh)
20628                };
20629                refresh_linked_ranges(self, window, cx);
20630                telemetry.log_edit_event("editor", is_via_ssh);
20631            }
20632            multi_buffer::Event::ExcerptsAdded {
20633                buffer,
20634                predecessor,
20635                excerpts,
20636            } => {
20637                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20638                let buffer_id = buffer.read(cx).remote_id();
20639                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20640                    && let Some(project) = &self.project
20641                {
20642                    update_uncommitted_diff_for_buffer(
20643                        cx.entity(),
20644                        project,
20645                        [buffer.clone()],
20646                        self.buffer.clone(),
20647                        cx,
20648                    )
20649                    .detach();
20650                }
20651                if self.active_diagnostics != ActiveDiagnostic::All {
20652                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20653                }
20654                cx.emit(EditorEvent::ExcerptsAdded {
20655                    buffer: buffer.clone(),
20656                    predecessor: *predecessor,
20657                    excerpts: excerpts.clone(),
20658                });
20659                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20660            }
20661            multi_buffer::Event::ExcerptsRemoved {
20662                ids,
20663                removed_buffer_ids,
20664            } => {
20665                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20666                let buffer = self.buffer.read(cx);
20667                self.registered_buffers
20668                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20669                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20670                cx.emit(EditorEvent::ExcerptsRemoved {
20671                    ids: ids.clone(),
20672                    removed_buffer_ids: removed_buffer_ids.clone(),
20673                });
20674            }
20675            multi_buffer::Event::ExcerptsEdited {
20676                excerpt_ids,
20677                buffer_ids,
20678            } => {
20679                self.display_map.update(cx, |map, cx| {
20680                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20681                });
20682                cx.emit(EditorEvent::ExcerptsEdited {
20683                    ids: excerpt_ids.clone(),
20684                });
20685            }
20686            multi_buffer::Event::ExcerptsExpanded { ids } => {
20687                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20688                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20689            }
20690            multi_buffer::Event::Reparsed(buffer_id) => {
20691                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20692                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20693
20694                cx.emit(EditorEvent::Reparsed(*buffer_id));
20695            }
20696            multi_buffer::Event::DiffHunksToggled => {
20697                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20698            }
20699            multi_buffer::Event::LanguageChanged(buffer_id) => {
20700                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20701                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20702                cx.emit(EditorEvent::Reparsed(*buffer_id));
20703                cx.notify();
20704            }
20705            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20706            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20707            multi_buffer::Event::FileHandleChanged
20708            | multi_buffer::Event::Reloaded
20709            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20710            multi_buffer::Event::DiagnosticsUpdated => {
20711                self.update_diagnostics_state(window, cx);
20712            }
20713            _ => {}
20714        };
20715    }
20716
20717    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20718        if !self.diagnostics_enabled() {
20719            return;
20720        }
20721        self.refresh_active_diagnostics(cx);
20722        self.refresh_inline_diagnostics(true, window, cx);
20723        self.scrollbar_marker_state.dirty = true;
20724        cx.notify();
20725    }
20726
20727    pub fn start_temporary_diff_override(&mut self) {
20728        self.load_diff_task.take();
20729        self.temporary_diff_override = true;
20730    }
20731
20732    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20733        self.temporary_diff_override = false;
20734        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20735        self.buffer.update(cx, |buffer, cx| {
20736            buffer.set_all_diff_hunks_collapsed(cx);
20737        });
20738
20739        if let Some(project) = self.project.clone() {
20740            self.load_diff_task = Some(
20741                update_uncommitted_diff_for_buffer(
20742                    cx.entity(),
20743                    &project,
20744                    self.buffer.read(cx).all_buffers(),
20745                    self.buffer.clone(),
20746                    cx,
20747                )
20748                .shared(),
20749            );
20750        }
20751    }
20752
20753    fn on_display_map_changed(
20754        &mut self,
20755        _: Entity<DisplayMap>,
20756        _: &mut Window,
20757        cx: &mut Context<Self>,
20758    ) {
20759        cx.notify();
20760    }
20761
20762    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20763        if self.diagnostics_enabled() {
20764            let new_severity = EditorSettings::get_global(cx)
20765                .diagnostics_max_severity
20766                .unwrap_or(DiagnosticSeverity::Hint);
20767            self.set_max_diagnostics_severity(new_severity, cx);
20768        }
20769        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20770        self.update_edit_prediction_settings(cx);
20771        self.refresh_edit_prediction(true, false, window, cx);
20772        self.refresh_inline_values(cx);
20773        self.refresh_inlay_hints(
20774            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20775                self.selections.newest_anchor().head(),
20776                &self.buffer.read(cx).snapshot(cx),
20777                cx,
20778            )),
20779            cx,
20780        );
20781
20782        let old_cursor_shape = self.cursor_shape;
20783        let old_show_breadcrumbs = self.show_breadcrumbs;
20784
20785        {
20786            let editor_settings = EditorSettings::get_global(cx);
20787            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20788            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20789            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20790            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20791        }
20792
20793        if old_cursor_shape != self.cursor_shape {
20794            cx.emit(EditorEvent::CursorShapeChanged);
20795        }
20796
20797        if old_show_breadcrumbs != self.show_breadcrumbs {
20798            cx.emit(EditorEvent::BreadcrumbsChanged);
20799        }
20800
20801        let project_settings = ProjectSettings::get_global(cx);
20802        self.serialize_dirty_buffers =
20803            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20804
20805        if self.mode.is_full() {
20806            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20807            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20808            if self.show_inline_diagnostics != show_inline_diagnostics {
20809                self.show_inline_diagnostics = show_inline_diagnostics;
20810                self.refresh_inline_diagnostics(false, window, cx);
20811            }
20812
20813            if self.git_blame_inline_enabled != inline_blame_enabled {
20814                self.toggle_git_blame_inline_internal(false, window, cx);
20815            }
20816
20817            let minimap_settings = EditorSettings::get_global(cx).minimap;
20818            if self.minimap_visibility != MinimapVisibility::Disabled {
20819                if self.minimap_visibility.settings_visibility()
20820                    != minimap_settings.minimap_enabled()
20821                {
20822                    self.set_minimap_visibility(
20823                        MinimapVisibility::for_mode(self.mode(), cx),
20824                        window,
20825                        cx,
20826                    );
20827                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20828                    minimap_entity.update(cx, |minimap_editor, cx| {
20829                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20830                    })
20831                }
20832            }
20833        }
20834
20835        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20836            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20837        }) {
20838            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20839                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20840            }
20841            self.refresh_colors(false, None, window, cx);
20842        }
20843
20844        cx.notify();
20845    }
20846
20847    pub fn set_searchable(&mut self, searchable: bool) {
20848        self.searchable = searchable;
20849    }
20850
20851    pub fn searchable(&self) -> bool {
20852        self.searchable
20853    }
20854
20855    fn open_proposed_changes_editor(
20856        &mut self,
20857        _: &OpenProposedChangesEditor,
20858        window: &mut Window,
20859        cx: &mut Context<Self>,
20860    ) {
20861        let Some(workspace) = self.workspace() else {
20862            cx.propagate();
20863            return;
20864        };
20865
20866        let selections = self.selections.all::<usize>(cx);
20867        let multi_buffer = self.buffer.read(cx);
20868        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20869        let mut new_selections_by_buffer = HashMap::default();
20870        for selection in selections {
20871            for (buffer, range, _) in
20872                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20873            {
20874                let mut range = range.to_point(buffer);
20875                range.start.column = 0;
20876                range.end.column = buffer.line_len(range.end.row);
20877                new_selections_by_buffer
20878                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20879                    .or_insert(Vec::new())
20880                    .push(range)
20881            }
20882        }
20883
20884        let proposed_changes_buffers = new_selections_by_buffer
20885            .into_iter()
20886            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20887            .collect::<Vec<_>>();
20888        let proposed_changes_editor = cx.new(|cx| {
20889            ProposedChangesEditor::new(
20890                "Proposed changes",
20891                proposed_changes_buffers,
20892                self.project.clone(),
20893                window,
20894                cx,
20895            )
20896        });
20897
20898        window.defer(cx, move |window, cx| {
20899            workspace.update(cx, |workspace, cx| {
20900                workspace.active_pane().update(cx, |pane, cx| {
20901                    pane.add_item(
20902                        Box::new(proposed_changes_editor),
20903                        true,
20904                        true,
20905                        None,
20906                        window,
20907                        cx,
20908                    );
20909                });
20910            });
20911        });
20912    }
20913
20914    pub fn open_excerpts_in_split(
20915        &mut self,
20916        _: &OpenExcerptsSplit,
20917        window: &mut Window,
20918        cx: &mut Context<Self>,
20919    ) {
20920        self.open_excerpts_common(None, true, window, cx)
20921    }
20922
20923    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20924        self.open_excerpts_common(None, false, window, cx)
20925    }
20926
20927    fn open_excerpts_common(
20928        &mut self,
20929        jump_data: Option<JumpData>,
20930        split: bool,
20931        window: &mut Window,
20932        cx: &mut Context<Self>,
20933    ) {
20934        let Some(workspace) = self.workspace() else {
20935            cx.propagate();
20936            return;
20937        };
20938
20939        if self.buffer.read(cx).is_singleton() {
20940            cx.propagate();
20941            return;
20942        }
20943
20944        let mut new_selections_by_buffer = HashMap::default();
20945        match &jump_data {
20946            Some(JumpData::MultiBufferPoint {
20947                excerpt_id,
20948                position,
20949                anchor,
20950                line_offset_from_top,
20951            }) => {
20952                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20953                if let Some(buffer) = multi_buffer_snapshot
20954                    .buffer_id_for_excerpt(*excerpt_id)
20955                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20956                {
20957                    let buffer_snapshot = buffer.read(cx).snapshot();
20958                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20959                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20960                    } else {
20961                        buffer_snapshot.clip_point(*position, Bias::Left)
20962                    };
20963                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20964                    new_selections_by_buffer.insert(
20965                        buffer,
20966                        (
20967                            vec![jump_to_offset..jump_to_offset],
20968                            Some(*line_offset_from_top),
20969                        ),
20970                    );
20971                }
20972            }
20973            Some(JumpData::MultiBufferRow {
20974                row,
20975                line_offset_from_top,
20976            }) => {
20977                let point = MultiBufferPoint::new(row.0, 0);
20978                if let Some((buffer, buffer_point, _)) =
20979                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20980                {
20981                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20982                    new_selections_by_buffer
20983                        .entry(buffer)
20984                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20985                        .0
20986                        .push(buffer_offset..buffer_offset)
20987                }
20988            }
20989            None => {
20990                let selections = self.selections.all::<usize>(cx);
20991                let multi_buffer = self.buffer.read(cx);
20992                for selection in selections {
20993                    for (snapshot, range, _, anchor) in multi_buffer
20994                        .snapshot(cx)
20995                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20996                    {
20997                        if let Some(anchor) = anchor {
20998                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20999                            else {
21000                                continue;
21001                            };
21002                            let offset = text::ToOffset::to_offset(
21003                                &anchor.text_anchor,
21004                                &buffer_handle.read(cx).snapshot(),
21005                            );
21006                            let range = offset..offset;
21007                            new_selections_by_buffer
21008                                .entry(buffer_handle)
21009                                .or_insert((Vec::new(), None))
21010                                .0
21011                                .push(range)
21012                        } else {
21013                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21014                            else {
21015                                continue;
21016                            };
21017                            new_selections_by_buffer
21018                                .entry(buffer_handle)
21019                                .or_insert((Vec::new(), None))
21020                                .0
21021                                .push(range)
21022                        }
21023                    }
21024                }
21025            }
21026        }
21027
21028        new_selections_by_buffer
21029            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21030
21031        if new_selections_by_buffer.is_empty() {
21032            return;
21033        }
21034
21035        // We defer the pane interaction because we ourselves are a workspace item
21036        // and activating a new item causes the pane to call a method on us reentrantly,
21037        // which panics if we're on the stack.
21038        window.defer(cx, move |window, cx| {
21039            workspace.update(cx, |workspace, cx| {
21040                let pane = if split {
21041                    workspace.adjacent_pane(window, cx)
21042                } else {
21043                    workspace.active_pane().clone()
21044                };
21045
21046                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21047                    let editor = buffer
21048                        .read(cx)
21049                        .file()
21050                        .is_none()
21051                        .then(|| {
21052                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21053                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21054                            // Instead, we try to activate the existing editor in the pane first.
21055                            let (editor, pane_item_index) =
21056                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21057                                    let editor = item.downcast::<Editor>()?;
21058                                    let singleton_buffer =
21059                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21060                                    if singleton_buffer == buffer {
21061                                        Some((editor, i))
21062                                    } else {
21063                                        None
21064                                    }
21065                                })?;
21066                            pane.update(cx, |pane, cx| {
21067                                pane.activate_item(pane_item_index, true, true, window, cx)
21068                            });
21069                            Some(editor)
21070                        })
21071                        .flatten()
21072                        .unwrap_or_else(|| {
21073                            workspace.open_project_item::<Self>(
21074                                pane.clone(),
21075                                buffer,
21076                                true,
21077                                true,
21078                                window,
21079                                cx,
21080                            )
21081                        });
21082
21083                    editor.update(cx, |editor, cx| {
21084                        let autoscroll = match scroll_offset {
21085                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21086                            None => Autoscroll::newest(),
21087                        };
21088                        let nav_history = editor.nav_history.take();
21089                        editor.change_selections(
21090                            SelectionEffects::scroll(autoscroll),
21091                            window,
21092                            cx,
21093                            |s| {
21094                                s.select_ranges(ranges);
21095                            },
21096                        );
21097                        editor.nav_history = nav_history;
21098                    });
21099                }
21100            })
21101        });
21102    }
21103
21104    // For now, don't allow opening excerpts in buffers that aren't backed by
21105    // regular project files.
21106    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21107        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21108    }
21109
21110    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21111        let snapshot = self.buffer.read(cx).read(cx);
21112        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21113        Some(
21114            ranges
21115                .iter()
21116                .map(move |range| {
21117                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21118                })
21119                .collect(),
21120        )
21121    }
21122
21123    fn selection_replacement_ranges(
21124        &self,
21125        range: Range<OffsetUtf16>,
21126        cx: &mut App,
21127    ) -> Vec<Range<OffsetUtf16>> {
21128        let selections = self.selections.all::<OffsetUtf16>(cx);
21129        let newest_selection = selections
21130            .iter()
21131            .max_by_key(|selection| selection.id)
21132            .unwrap();
21133        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21134        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21135        let snapshot = self.buffer.read(cx).read(cx);
21136        selections
21137            .into_iter()
21138            .map(|mut selection| {
21139                selection.start.0 =
21140                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21141                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21142                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21143                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21144            })
21145            .collect()
21146    }
21147
21148    fn report_editor_event(
21149        &self,
21150        reported_event: ReportEditorEvent,
21151        file_extension: Option<String>,
21152        cx: &App,
21153    ) {
21154        if cfg!(any(test, feature = "test-support")) {
21155            return;
21156        }
21157
21158        let Some(project) = &self.project else { return };
21159
21160        // If None, we are in a file without an extension
21161        let file = self
21162            .buffer
21163            .read(cx)
21164            .as_singleton()
21165            .and_then(|b| b.read(cx).file());
21166        let file_extension = file_extension.or(file
21167            .as_ref()
21168            .and_then(|file| Path::new(file.file_name(cx)).extension())
21169            .and_then(|e| e.to_str())
21170            .map(|a| a.to_string()));
21171
21172        let vim_mode = vim_enabled(cx);
21173
21174        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21175        let copilot_enabled = edit_predictions_provider
21176            == language::language_settings::EditPredictionProvider::Copilot;
21177        let copilot_enabled_for_language = self
21178            .buffer
21179            .read(cx)
21180            .language_settings(cx)
21181            .show_edit_predictions;
21182
21183        let project = project.read(cx);
21184        let event_type = reported_event.event_type();
21185
21186        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21187            telemetry::event!(
21188                event_type,
21189                type = if auto_saved {"autosave"} else {"manual"},
21190                file_extension,
21191                vim_mode,
21192                copilot_enabled,
21193                copilot_enabled_for_language,
21194                edit_predictions_provider,
21195                is_via_ssh = project.is_via_remote_server(),
21196            );
21197        } else {
21198            telemetry::event!(
21199                event_type,
21200                file_extension,
21201                vim_mode,
21202                copilot_enabled,
21203                copilot_enabled_for_language,
21204                edit_predictions_provider,
21205                is_via_ssh = project.is_via_remote_server(),
21206            );
21207        };
21208    }
21209
21210    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21211    /// with each line being an array of {text, highlight} objects.
21212    fn copy_highlight_json(
21213        &mut self,
21214        _: &CopyHighlightJson,
21215        window: &mut Window,
21216        cx: &mut Context<Self>,
21217    ) {
21218        #[derive(Serialize)]
21219        struct Chunk<'a> {
21220            text: String,
21221            highlight: Option<&'a str>,
21222        }
21223
21224        let snapshot = self.buffer.read(cx).snapshot(cx);
21225        let range = self
21226            .selected_text_range(false, window, cx)
21227            .and_then(|selection| {
21228                if selection.range.is_empty() {
21229                    None
21230                } else {
21231                    Some(selection.range)
21232                }
21233            })
21234            .unwrap_or_else(|| 0..snapshot.len());
21235
21236        let chunks = snapshot.chunks(range, true);
21237        let mut lines = Vec::new();
21238        let mut line: VecDeque<Chunk> = VecDeque::new();
21239
21240        let Some(style) = self.style.as_ref() else {
21241            return;
21242        };
21243
21244        for chunk in chunks {
21245            let highlight = chunk
21246                .syntax_highlight_id
21247                .and_then(|id| id.name(&style.syntax));
21248            let mut chunk_lines = chunk.text.split('\n').peekable();
21249            while let Some(text) = chunk_lines.next() {
21250                let mut merged_with_last_token = false;
21251                if let Some(last_token) = line.back_mut()
21252                    && last_token.highlight == highlight
21253                {
21254                    last_token.text.push_str(text);
21255                    merged_with_last_token = true;
21256                }
21257
21258                if !merged_with_last_token {
21259                    line.push_back(Chunk {
21260                        text: text.into(),
21261                        highlight,
21262                    });
21263                }
21264
21265                if chunk_lines.peek().is_some() {
21266                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21267                        line.pop_front();
21268                    }
21269                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21270                        line.pop_back();
21271                    }
21272
21273                    lines.push(mem::take(&mut line));
21274                }
21275            }
21276        }
21277
21278        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21279            return;
21280        };
21281        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21282    }
21283
21284    pub fn open_context_menu(
21285        &mut self,
21286        _: &OpenContextMenu,
21287        window: &mut Window,
21288        cx: &mut Context<Self>,
21289    ) {
21290        self.request_autoscroll(Autoscroll::newest(), cx);
21291        let position = self.selections.newest_display(cx).start;
21292        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21293    }
21294
21295    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21296        &self.inlay_hint_cache
21297    }
21298
21299    pub fn replay_insert_event(
21300        &mut self,
21301        text: &str,
21302        relative_utf16_range: Option<Range<isize>>,
21303        window: &mut Window,
21304        cx: &mut Context<Self>,
21305    ) {
21306        if !self.input_enabled {
21307            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21308            return;
21309        }
21310        if let Some(relative_utf16_range) = relative_utf16_range {
21311            let selections = self.selections.all::<OffsetUtf16>(cx);
21312            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21313                let new_ranges = selections.into_iter().map(|range| {
21314                    let start = OffsetUtf16(
21315                        range
21316                            .head()
21317                            .0
21318                            .saturating_add_signed(relative_utf16_range.start),
21319                    );
21320                    let end = OffsetUtf16(
21321                        range
21322                            .head()
21323                            .0
21324                            .saturating_add_signed(relative_utf16_range.end),
21325                    );
21326                    start..end
21327                });
21328                s.select_ranges(new_ranges);
21329            });
21330        }
21331
21332        self.handle_input(text, window, cx);
21333    }
21334
21335    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21336        let Some(provider) = self.semantics_provider.as_ref() else {
21337            return false;
21338        };
21339
21340        let mut supports = false;
21341        self.buffer().update(cx, |this, cx| {
21342            this.for_each_buffer(|buffer| {
21343                supports |= provider.supports_inlay_hints(buffer, cx);
21344            });
21345        });
21346
21347        supports
21348    }
21349
21350    pub fn is_focused(&self, window: &Window) -> bool {
21351        self.focus_handle.is_focused(window)
21352    }
21353
21354    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21355        cx.emit(EditorEvent::Focused);
21356
21357        if let Some(descendant) = self
21358            .last_focused_descendant
21359            .take()
21360            .and_then(|descendant| descendant.upgrade())
21361        {
21362            window.focus(&descendant);
21363        } else {
21364            if let Some(blame) = self.blame.as_ref() {
21365                blame.update(cx, GitBlame::focus)
21366            }
21367
21368            self.blink_manager.update(cx, BlinkManager::enable);
21369            self.show_cursor_names(window, cx);
21370            self.buffer.update(cx, |buffer, cx| {
21371                buffer.finalize_last_transaction(cx);
21372                if self.leader_id.is_none() {
21373                    buffer.set_active_selections(
21374                        &self.selections.disjoint_anchors_arc(),
21375                        self.selections.line_mode(),
21376                        self.cursor_shape,
21377                        cx,
21378                    );
21379                }
21380            });
21381        }
21382    }
21383
21384    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21385        cx.emit(EditorEvent::FocusedIn)
21386    }
21387
21388    fn handle_focus_out(
21389        &mut self,
21390        event: FocusOutEvent,
21391        _window: &mut Window,
21392        cx: &mut Context<Self>,
21393    ) {
21394        if event.blurred != self.focus_handle {
21395            self.last_focused_descendant = Some(event.blurred);
21396        }
21397        self.selection_drag_state = SelectionDragState::None;
21398        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21399    }
21400
21401    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21402        self.blink_manager.update(cx, BlinkManager::disable);
21403        self.buffer
21404            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21405
21406        if let Some(blame) = self.blame.as_ref() {
21407            blame.update(cx, GitBlame::blur)
21408        }
21409        if !self.hover_state.focused(window, cx) {
21410            hide_hover(self, cx);
21411        }
21412        if !self
21413            .context_menu
21414            .borrow()
21415            .as_ref()
21416            .is_some_and(|context_menu| context_menu.focused(window, cx))
21417        {
21418            self.hide_context_menu(window, cx);
21419        }
21420        self.discard_edit_prediction(false, cx);
21421        cx.emit(EditorEvent::Blurred);
21422        cx.notify();
21423    }
21424
21425    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21426        let mut pending: String = window
21427            .pending_input_keystrokes()
21428            .into_iter()
21429            .flatten()
21430            .filter_map(|keystroke| {
21431                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21432                    keystroke.key_char.clone()
21433                } else {
21434                    None
21435                }
21436            })
21437            .collect();
21438
21439        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21440            pending = "".to_string();
21441        }
21442
21443        let existing_pending = self
21444            .text_highlights::<PendingInput>(cx)
21445            .map(|(_, ranges)| ranges.to_vec());
21446        if existing_pending.is_none() && pending.is_empty() {
21447            return;
21448        }
21449        let transaction =
21450            self.transact(window, cx, |this, window, cx| {
21451                let selections = this.selections.all::<usize>(cx);
21452                let edits = selections
21453                    .iter()
21454                    .map(|selection| (selection.end..selection.end, pending.clone()));
21455                this.edit(edits, cx);
21456                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21457                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21458                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21459                    }));
21460                });
21461                if let Some(existing_ranges) = existing_pending {
21462                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21463                    this.edit(edits, cx);
21464                }
21465            });
21466
21467        let snapshot = self.snapshot(window, cx);
21468        let ranges = self
21469            .selections
21470            .all::<usize>(cx)
21471            .into_iter()
21472            .map(|selection| {
21473                snapshot.buffer_snapshot.anchor_after(selection.end)
21474                    ..snapshot
21475                        .buffer_snapshot
21476                        .anchor_before(selection.end + pending.len())
21477            })
21478            .collect();
21479
21480        if pending.is_empty() {
21481            self.clear_highlights::<PendingInput>(cx);
21482        } else {
21483            self.highlight_text::<PendingInput>(
21484                ranges,
21485                HighlightStyle {
21486                    underline: Some(UnderlineStyle {
21487                        thickness: px(1.),
21488                        color: None,
21489                        wavy: false,
21490                    }),
21491                    ..Default::default()
21492                },
21493                cx,
21494            );
21495        }
21496
21497        self.ime_transaction = self.ime_transaction.or(transaction);
21498        if let Some(transaction) = self.ime_transaction {
21499            self.buffer.update(cx, |buffer, cx| {
21500                buffer.group_until_transaction(transaction, cx);
21501            });
21502        }
21503
21504        if self.text_highlights::<PendingInput>(cx).is_none() {
21505            self.ime_transaction.take();
21506        }
21507    }
21508
21509    pub fn register_action_renderer(
21510        &mut self,
21511        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21512    ) -> Subscription {
21513        let id = self.next_editor_action_id.post_inc();
21514        self.editor_actions
21515            .borrow_mut()
21516            .insert(id, Box::new(listener));
21517
21518        let editor_actions = self.editor_actions.clone();
21519        Subscription::new(move || {
21520            editor_actions.borrow_mut().remove(&id);
21521        })
21522    }
21523
21524    pub fn register_action<A: Action>(
21525        &mut self,
21526        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21527    ) -> Subscription {
21528        let id = self.next_editor_action_id.post_inc();
21529        let listener = Arc::new(listener);
21530        self.editor_actions.borrow_mut().insert(
21531            id,
21532            Box::new(move |_, window, _| {
21533                let listener = listener.clone();
21534                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21535                    let action = action.downcast_ref().unwrap();
21536                    if phase == DispatchPhase::Bubble {
21537                        listener(action, window, cx)
21538                    }
21539                })
21540            }),
21541        );
21542
21543        let editor_actions = self.editor_actions.clone();
21544        Subscription::new(move || {
21545            editor_actions.borrow_mut().remove(&id);
21546        })
21547    }
21548
21549    pub fn file_header_size(&self) -> u32 {
21550        FILE_HEADER_HEIGHT
21551    }
21552
21553    pub fn restore(
21554        &mut self,
21555        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21556        window: &mut Window,
21557        cx: &mut Context<Self>,
21558    ) {
21559        let workspace = self.workspace();
21560        let project = self.project();
21561        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21562            let mut tasks = Vec::new();
21563            for (buffer_id, changes) in revert_changes {
21564                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21565                    buffer.update(cx, |buffer, cx| {
21566                        buffer.edit(
21567                            changes
21568                                .into_iter()
21569                                .map(|(range, text)| (range, text.to_string())),
21570                            None,
21571                            cx,
21572                        );
21573                    });
21574
21575                    if let Some(project) =
21576                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21577                    {
21578                        project.update(cx, |project, cx| {
21579                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21580                        })
21581                    }
21582                }
21583            }
21584            tasks
21585        });
21586        cx.spawn_in(window, async move |_, cx| {
21587            for (buffer, task) in save_tasks {
21588                let result = task.await;
21589                if result.is_err() {
21590                    let Some(path) = buffer
21591                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21592                        .ok()
21593                    else {
21594                        continue;
21595                    };
21596                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21597                        let Some(task) = cx
21598                            .update_window_entity(workspace, |workspace, window, cx| {
21599                                workspace
21600                                    .open_path_preview(path, None, false, false, false, window, cx)
21601                            })
21602                            .ok()
21603                        else {
21604                            continue;
21605                        };
21606                        task.await.log_err();
21607                    }
21608                }
21609            }
21610        })
21611        .detach();
21612        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21613            selections.refresh()
21614        });
21615    }
21616
21617    pub fn to_pixel_point(
21618        &self,
21619        source: multi_buffer::Anchor,
21620        editor_snapshot: &EditorSnapshot,
21621        window: &mut Window,
21622    ) -> Option<gpui::Point<Pixels>> {
21623        let source_point = source.to_display_point(editor_snapshot);
21624        self.display_to_pixel_point(source_point, editor_snapshot, window)
21625    }
21626
21627    pub fn display_to_pixel_point(
21628        &self,
21629        source: DisplayPoint,
21630        editor_snapshot: &EditorSnapshot,
21631        window: &mut Window,
21632    ) -> Option<gpui::Point<Pixels>> {
21633        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21634        let text_layout_details = self.text_layout_details(window);
21635        let scroll_top = text_layout_details
21636            .scroll_anchor
21637            .scroll_position(editor_snapshot)
21638            .y;
21639
21640        if source.row().as_f32() < scroll_top.floor() {
21641            return None;
21642        }
21643        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21644        let source_y = line_height * (source.row().as_f32() - scroll_top);
21645        Some(gpui::Point::new(source_x, source_y))
21646    }
21647
21648    pub fn has_visible_completions_menu(&self) -> bool {
21649        !self.edit_prediction_preview_is_active()
21650            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21651                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21652            })
21653    }
21654
21655    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21656        if self.mode.is_minimap() {
21657            return;
21658        }
21659        self.addons
21660            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21661    }
21662
21663    pub fn unregister_addon<T: Addon>(&mut self) {
21664        self.addons.remove(&std::any::TypeId::of::<T>());
21665    }
21666
21667    pub fn addon<T: Addon>(&self) -> Option<&T> {
21668        let type_id = std::any::TypeId::of::<T>();
21669        self.addons
21670            .get(&type_id)
21671            .and_then(|item| item.to_any().downcast_ref::<T>())
21672    }
21673
21674    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21675        let type_id = std::any::TypeId::of::<T>();
21676        self.addons
21677            .get_mut(&type_id)
21678            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21679    }
21680
21681    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21682        let text_layout_details = self.text_layout_details(window);
21683        let style = &text_layout_details.editor_style;
21684        let font_id = window.text_system().resolve_font(&style.text.font());
21685        let font_size = style.text.font_size.to_pixels(window.rem_size());
21686        let line_height = style.text.line_height_in_pixels(window.rem_size());
21687        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21688        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21689
21690        CharacterDimensions {
21691            em_width,
21692            em_advance,
21693            line_height,
21694        }
21695    }
21696
21697    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21698        self.load_diff_task.clone()
21699    }
21700
21701    fn read_metadata_from_db(
21702        &mut self,
21703        item_id: u64,
21704        workspace_id: WorkspaceId,
21705        window: &mut Window,
21706        cx: &mut Context<Editor>,
21707    ) {
21708        if self.is_singleton(cx)
21709            && !self.mode.is_minimap()
21710            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21711        {
21712            let buffer_snapshot = OnceCell::new();
21713
21714            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21715                && !folds.is_empty()
21716            {
21717                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21718                self.fold_ranges(
21719                    folds
21720                        .into_iter()
21721                        .map(|(start, end)| {
21722                            snapshot.clip_offset(start, Bias::Left)
21723                                ..snapshot.clip_offset(end, Bias::Right)
21724                        })
21725                        .collect(),
21726                    false,
21727                    window,
21728                    cx,
21729                );
21730            }
21731
21732            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21733                && !selections.is_empty()
21734            {
21735                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21736                // skip adding the initial selection to selection history
21737                self.selection_history.mode = SelectionHistoryMode::Skipping;
21738                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21739                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21740                        snapshot.clip_offset(start, Bias::Left)
21741                            ..snapshot.clip_offset(end, Bias::Right)
21742                    }));
21743                });
21744                self.selection_history.mode = SelectionHistoryMode::Normal;
21745            };
21746        }
21747
21748        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21749    }
21750
21751    fn update_lsp_data(
21752        &mut self,
21753        ignore_cache: bool,
21754        for_buffer: Option<BufferId>,
21755        window: &mut Window,
21756        cx: &mut Context<'_, Self>,
21757    ) {
21758        self.pull_diagnostics(for_buffer, window, cx);
21759        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21760    }
21761}
21762
21763fn edit_for_markdown_paste<'a>(
21764    buffer: &MultiBufferSnapshot,
21765    range: Range<usize>,
21766    to_insert: &'a str,
21767    url: Option<url::Url>,
21768) -> (Range<usize>, Cow<'a, str>) {
21769    if url.is_none() {
21770        return (range, Cow::Borrowed(to_insert));
21771    };
21772
21773    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21774
21775    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21776        Cow::Borrowed(to_insert)
21777    } else {
21778        Cow::Owned(format!("[{old_text}]({to_insert})"))
21779    };
21780    (range, new_text)
21781}
21782
21783fn vim_enabled(cx: &App) -> bool {
21784    vim_mode_setting::VimModeSetting::try_get(cx)
21785        .map(|vim_mode| vim_mode.0)
21786        .unwrap_or(false)
21787}
21788
21789fn process_completion_for_edit(
21790    completion: &Completion,
21791    intent: CompletionIntent,
21792    buffer: &Entity<Buffer>,
21793    cursor_position: &text::Anchor,
21794    cx: &mut Context<Editor>,
21795) -> CompletionEdit {
21796    let buffer = buffer.read(cx);
21797    let buffer_snapshot = buffer.snapshot();
21798    let (snippet, new_text) = if completion.is_snippet() {
21799        // Workaround for typescript language server issues so that methods don't expand within
21800        // strings and functions with type expressions. The previous point is used because the query
21801        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21802        let mut snippet_source = completion.new_text.clone();
21803        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21804        previous_point.column = previous_point.column.saturating_sub(1);
21805        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21806            && scope.prefers_label_for_snippet_in_completion()
21807            && let Some(label) = completion.label()
21808            && matches!(
21809                completion.kind(),
21810                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21811            )
21812        {
21813            snippet_source = label;
21814        }
21815        match Snippet::parse(&snippet_source).log_err() {
21816            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21817            None => (None, completion.new_text.clone()),
21818        }
21819    } else {
21820        (None, completion.new_text.clone())
21821    };
21822
21823    let mut range_to_replace = {
21824        let replace_range = &completion.replace_range;
21825        if let CompletionSource::Lsp {
21826            insert_range: Some(insert_range),
21827            ..
21828        } = &completion.source
21829        {
21830            debug_assert_eq!(
21831                insert_range.start, replace_range.start,
21832                "insert_range and replace_range should start at the same position"
21833            );
21834            debug_assert!(
21835                insert_range
21836                    .start
21837                    .cmp(cursor_position, &buffer_snapshot)
21838                    .is_le(),
21839                "insert_range should start before or at cursor position"
21840            );
21841            debug_assert!(
21842                replace_range
21843                    .start
21844                    .cmp(cursor_position, &buffer_snapshot)
21845                    .is_le(),
21846                "replace_range should start before or at cursor position"
21847            );
21848
21849            let should_replace = match intent {
21850                CompletionIntent::CompleteWithInsert => false,
21851                CompletionIntent::CompleteWithReplace => true,
21852                CompletionIntent::Complete | CompletionIntent::Compose => {
21853                    let insert_mode =
21854                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21855                            .completions
21856                            .lsp_insert_mode;
21857                    match insert_mode {
21858                        LspInsertMode::Insert => false,
21859                        LspInsertMode::Replace => true,
21860                        LspInsertMode::ReplaceSubsequence => {
21861                            let mut text_to_replace = buffer.chars_for_range(
21862                                buffer.anchor_before(replace_range.start)
21863                                    ..buffer.anchor_after(replace_range.end),
21864                            );
21865                            let mut current_needle = text_to_replace.next();
21866                            for haystack_ch in completion.label.text.chars() {
21867                                if let Some(needle_ch) = current_needle
21868                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21869                                {
21870                                    current_needle = text_to_replace.next();
21871                                }
21872                            }
21873                            current_needle.is_none()
21874                        }
21875                        LspInsertMode::ReplaceSuffix => {
21876                            if replace_range
21877                                .end
21878                                .cmp(cursor_position, &buffer_snapshot)
21879                                .is_gt()
21880                            {
21881                                let range_after_cursor = *cursor_position..replace_range.end;
21882                                let text_after_cursor = buffer
21883                                    .text_for_range(
21884                                        buffer.anchor_before(range_after_cursor.start)
21885                                            ..buffer.anchor_after(range_after_cursor.end),
21886                                    )
21887                                    .collect::<String>()
21888                                    .to_ascii_lowercase();
21889                                completion
21890                                    .label
21891                                    .text
21892                                    .to_ascii_lowercase()
21893                                    .ends_with(&text_after_cursor)
21894                            } else {
21895                                true
21896                            }
21897                        }
21898                    }
21899                }
21900            };
21901
21902            if should_replace {
21903                replace_range.clone()
21904            } else {
21905                insert_range.clone()
21906            }
21907        } else {
21908            replace_range.clone()
21909        }
21910    };
21911
21912    if range_to_replace
21913        .end
21914        .cmp(cursor_position, &buffer_snapshot)
21915        .is_lt()
21916    {
21917        range_to_replace.end = *cursor_position;
21918    }
21919
21920    CompletionEdit {
21921        new_text,
21922        replace_range: range_to_replace.to_offset(buffer),
21923        snippet,
21924    }
21925}
21926
21927struct CompletionEdit {
21928    new_text: String,
21929    replace_range: Range<usize>,
21930    snippet: Option<Snippet>,
21931}
21932
21933fn insert_extra_newline_brackets(
21934    buffer: &MultiBufferSnapshot,
21935    range: Range<usize>,
21936    language: &language::LanguageScope,
21937) -> bool {
21938    let leading_whitespace_len = buffer
21939        .reversed_chars_at(range.start)
21940        .take_while(|c| c.is_whitespace() && *c != '\n')
21941        .map(|c| c.len_utf8())
21942        .sum::<usize>();
21943    let trailing_whitespace_len = buffer
21944        .chars_at(range.end)
21945        .take_while(|c| c.is_whitespace() && *c != '\n')
21946        .map(|c| c.len_utf8())
21947        .sum::<usize>();
21948    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21949
21950    language.brackets().any(|(pair, enabled)| {
21951        let pair_start = pair.start.trim_end();
21952        let pair_end = pair.end.trim_start();
21953
21954        enabled
21955            && pair.newline
21956            && buffer.contains_str_at(range.end, pair_end)
21957            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21958    })
21959}
21960
21961fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21962    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21963        [(buffer, range, _)] => (*buffer, range.clone()),
21964        _ => return false,
21965    };
21966    let pair = {
21967        let mut result: Option<BracketMatch> = None;
21968
21969        for pair in buffer
21970            .all_bracket_ranges(range.clone())
21971            .filter(move |pair| {
21972                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21973            })
21974        {
21975            let len = pair.close_range.end - pair.open_range.start;
21976
21977            if let Some(existing) = &result {
21978                let existing_len = existing.close_range.end - existing.open_range.start;
21979                if len > existing_len {
21980                    continue;
21981                }
21982            }
21983
21984            result = Some(pair);
21985        }
21986
21987        result
21988    };
21989    let Some(pair) = pair else {
21990        return false;
21991    };
21992    pair.newline_only
21993        && buffer
21994            .chars_for_range(pair.open_range.end..range.start)
21995            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21996            .all(|c| c.is_whitespace() && c != '\n')
21997}
21998
21999fn update_uncommitted_diff_for_buffer(
22000    editor: Entity<Editor>,
22001    project: &Entity<Project>,
22002    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22003    buffer: Entity<MultiBuffer>,
22004    cx: &mut App,
22005) -> Task<()> {
22006    let mut tasks = Vec::new();
22007    project.update(cx, |project, cx| {
22008        for buffer in buffers {
22009            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22010                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22011            }
22012        }
22013    });
22014    cx.spawn(async move |cx| {
22015        let diffs = future::join_all(tasks).await;
22016        if editor
22017            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22018            .unwrap_or(false)
22019        {
22020            return;
22021        }
22022
22023        buffer
22024            .update(cx, |buffer, cx| {
22025                for diff in diffs.into_iter().flatten() {
22026                    buffer.add_diff(diff, cx);
22027                }
22028            })
22029            .ok();
22030    })
22031}
22032
22033fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22034    let tab_size = tab_size.get() as usize;
22035    let mut width = offset;
22036
22037    for ch in text.chars() {
22038        width += if ch == '\t' {
22039            tab_size - (width % tab_size)
22040        } else {
22041            1
22042        };
22043    }
22044
22045    width - offset
22046}
22047
22048#[cfg(test)]
22049mod tests {
22050    use super::*;
22051
22052    #[test]
22053    fn test_string_size_with_expanded_tabs() {
22054        let nz = |val| NonZeroU32::new(val).unwrap();
22055        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22056        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22057        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22058        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22059        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22060        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22061        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22062        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22063    }
22064}
22065
22066/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22067struct WordBreakingTokenizer<'a> {
22068    input: &'a str,
22069}
22070
22071impl<'a> WordBreakingTokenizer<'a> {
22072    fn new(input: &'a str) -> Self {
22073        Self { input }
22074    }
22075}
22076
22077fn is_char_ideographic(ch: char) -> bool {
22078    use unicode_script::Script::*;
22079    use unicode_script::UnicodeScript;
22080    matches!(ch.script(), Han | Tangut | Yi)
22081}
22082
22083fn is_grapheme_ideographic(text: &str) -> bool {
22084    text.chars().any(is_char_ideographic)
22085}
22086
22087fn is_grapheme_whitespace(text: &str) -> bool {
22088    text.chars().any(|x| x.is_whitespace())
22089}
22090
22091fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22092    text.chars()
22093        .next()
22094        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22095}
22096
22097#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22098enum WordBreakToken<'a> {
22099    Word { token: &'a str, grapheme_len: usize },
22100    InlineWhitespace { token: &'a str, grapheme_len: usize },
22101    Newline,
22102}
22103
22104impl<'a> Iterator for WordBreakingTokenizer<'a> {
22105    /// Yields a span, the count of graphemes in the token, and whether it was
22106    /// whitespace. Note that it also breaks at word boundaries.
22107    type Item = WordBreakToken<'a>;
22108
22109    fn next(&mut self) -> Option<Self::Item> {
22110        use unicode_segmentation::UnicodeSegmentation;
22111        if self.input.is_empty() {
22112            return None;
22113        }
22114
22115        let mut iter = self.input.graphemes(true).peekable();
22116        let mut offset = 0;
22117        let mut grapheme_len = 0;
22118        if let Some(first_grapheme) = iter.next() {
22119            let is_newline = first_grapheme == "\n";
22120            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22121            offset += first_grapheme.len();
22122            grapheme_len += 1;
22123            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22124                if let Some(grapheme) = iter.peek().copied()
22125                    && should_stay_with_preceding_ideograph(grapheme)
22126                {
22127                    offset += grapheme.len();
22128                    grapheme_len += 1;
22129                }
22130            } else {
22131                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22132                let mut next_word_bound = words.peek().copied();
22133                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22134                    next_word_bound = words.next();
22135                }
22136                while let Some(grapheme) = iter.peek().copied() {
22137                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22138                        break;
22139                    };
22140                    if is_grapheme_whitespace(grapheme) != is_whitespace
22141                        || (grapheme == "\n") != is_newline
22142                    {
22143                        break;
22144                    };
22145                    offset += grapheme.len();
22146                    grapheme_len += 1;
22147                    iter.next();
22148                }
22149            }
22150            let token = &self.input[..offset];
22151            self.input = &self.input[offset..];
22152            if token == "\n" {
22153                Some(WordBreakToken::Newline)
22154            } else if is_whitespace {
22155                Some(WordBreakToken::InlineWhitespace {
22156                    token,
22157                    grapheme_len,
22158                })
22159            } else {
22160                Some(WordBreakToken::Word {
22161                    token,
22162                    grapheme_len,
22163                })
22164            }
22165        } else {
22166            None
22167        }
22168    }
22169}
22170
22171#[test]
22172fn test_word_breaking_tokenizer() {
22173    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22174        ("", &[]),
22175        ("  ", &[whitespace("  ", 2)]),
22176        ("Ʒ", &[word("Ʒ", 1)]),
22177        ("Ǽ", &[word("Ǽ", 1)]),
22178        ("", &[word("", 1)]),
22179        ("⋑⋑", &[word("⋑⋑", 2)]),
22180        (
22181            "原理,进而",
22182            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22183        ),
22184        (
22185            "hello world",
22186            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22187        ),
22188        (
22189            "hello, world",
22190            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22191        ),
22192        (
22193            "  hello world",
22194            &[
22195                whitespace("  ", 2),
22196                word("hello", 5),
22197                whitespace(" ", 1),
22198                word("world", 5),
22199            ],
22200        ),
22201        (
22202            "这是什么 \n 钢笔",
22203            &[
22204                word("", 1),
22205                word("", 1),
22206                word("", 1),
22207                word("", 1),
22208                whitespace(" ", 1),
22209                newline(),
22210                whitespace(" ", 1),
22211                word("", 1),
22212                word("", 1),
22213            ],
22214        ),
22215        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22216    ];
22217
22218    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22219        WordBreakToken::Word {
22220            token,
22221            grapheme_len,
22222        }
22223    }
22224
22225    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22226        WordBreakToken::InlineWhitespace {
22227            token,
22228            grapheme_len,
22229        }
22230    }
22231
22232    fn newline() -> WordBreakToken<'static> {
22233        WordBreakToken::Newline
22234    }
22235
22236    for (input, result) in tests {
22237        assert_eq!(
22238            WordBreakingTokenizer::new(input)
22239                .collect::<Vec<_>>()
22240                .as_slice(),
22241            *result,
22242        );
22243    }
22244}
22245
22246fn wrap_with_prefix(
22247    first_line_prefix: String,
22248    subsequent_lines_prefix: String,
22249    unwrapped_text: String,
22250    wrap_column: usize,
22251    tab_size: NonZeroU32,
22252    preserve_existing_whitespace: bool,
22253) -> String {
22254    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22255    let subsequent_lines_prefix_len =
22256        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22257    let mut wrapped_text = String::new();
22258    let mut current_line = first_line_prefix;
22259    let mut is_first_line = true;
22260
22261    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22262    let mut current_line_len = first_line_prefix_len;
22263    let mut in_whitespace = false;
22264    for token in tokenizer {
22265        let have_preceding_whitespace = in_whitespace;
22266        match token {
22267            WordBreakToken::Word {
22268                token,
22269                grapheme_len,
22270            } => {
22271                in_whitespace = false;
22272                let current_prefix_len = if is_first_line {
22273                    first_line_prefix_len
22274                } else {
22275                    subsequent_lines_prefix_len
22276                };
22277                if current_line_len + grapheme_len > wrap_column
22278                    && current_line_len != current_prefix_len
22279                {
22280                    wrapped_text.push_str(current_line.trim_end());
22281                    wrapped_text.push('\n');
22282                    is_first_line = false;
22283                    current_line = subsequent_lines_prefix.clone();
22284                    current_line_len = subsequent_lines_prefix_len;
22285                }
22286                current_line.push_str(token);
22287                current_line_len += grapheme_len;
22288            }
22289            WordBreakToken::InlineWhitespace {
22290                mut token,
22291                mut grapheme_len,
22292            } => {
22293                in_whitespace = true;
22294                if have_preceding_whitespace && !preserve_existing_whitespace {
22295                    continue;
22296                }
22297                if !preserve_existing_whitespace {
22298                    token = " ";
22299                    grapheme_len = 1;
22300                }
22301                let current_prefix_len = if is_first_line {
22302                    first_line_prefix_len
22303                } else {
22304                    subsequent_lines_prefix_len
22305                };
22306                if current_line_len + grapheme_len > wrap_column {
22307                    wrapped_text.push_str(current_line.trim_end());
22308                    wrapped_text.push('\n');
22309                    is_first_line = false;
22310                    current_line = subsequent_lines_prefix.clone();
22311                    current_line_len = subsequent_lines_prefix_len;
22312                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22313                    current_line.push_str(token);
22314                    current_line_len += grapheme_len;
22315                }
22316            }
22317            WordBreakToken::Newline => {
22318                in_whitespace = true;
22319                let current_prefix_len = if is_first_line {
22320                    first_line_prefix_len
22321                } else {
22322                    subsequent_lines_prefix_len
22323                };
22324                if preserve_existing_whitespace {
22325                    wrapped_text.push_str(current_line.trim_end());
22326                    wrapped_text.push('\n');
22327                    is_first_line = false;
22328                    current_line = subsequent_lines_prefix.clone();
22329                    current_line_len = subsequent_lines_prefix_len;
22330                } else if have_preceding_whitespace {
22331                    continue;
22332                } else if current_line_len + 1 > wrap_column
22333                    && current_line_len != current_prefix_len
22334                {
22335                    wrapped_text.push_str(current_line.trim_end());
22336                    wrapped_text.push('\n');
22337                    is_first_line = false;
22338                    current_line = subsequent_lines_prefix.clone();
22339                    current_line_len = subsequent_lines_prefix_len;
22340                } else if current_line_len != current_prefix_len {
22341                    current_line.push(' ');
22342                    current_line_len += 1;
22343                }
22344            }
22345        }
22346    }
22347
22348    if !current_line.is_empty() {
22349        wrapped_text.push_str(&current_line);
22350    }
22351    wrapped_text
22352}
22353
22354#[test]
22355fn test_wrap_with_prefix() {
22356    assert_eq!(
22357        wrap_with_prefix(
22358            "# ".to_string(),
22359            "# ".to_string(),
22360            "abcdefg".to_string(),
22361            4,
22362            NonZeroU32::new(4).unwrap(),
22363            false,
22364        ),
22365        "# abcdefg"
22366    );
22367    assert_eq!(
22368        wrap_with_prefix(
22369            "".to_string(),
22370            "".to_string(),
22371            "\thello world".to_string(),
22372            8,
22373            NonZeroU32::new(4).unwrap(),
22374            false,
22375        ),
22376        "hello\nworld"
22377    );
22378    assert_eq!(
22379        wrap_with_prefix(
22380            "// ".to_string(),
22381            "// ".to_string(),
22382            "xx \nyy zz aa bb cc".to_string(),
22383            12,
22384            NonZeroU32::new(4).unwrap(),
22385            false,
22386        ),
22387        "// xx yy zz\n// aa bb cc"
22388    );
22389    assert_eq!(
22390        wrap_with_prefix(
22391            String::new(),
22392            String::new(),
22393            "这是什么 \n 钢笔".to_string(),
22394            3,
22395            NonZeroU32::new(4).unwrap(),
22396            false,
22397        ),
22398        "这是什\n么 钢\n"
22399    );
22400}
22401
22402pub trait CollaborationHub {
22403    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22404    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22405    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22406}
22407
22408impl CollaborationHub for Entity<Project> {
22409    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22410        self.read(cx).collaborators()
22411    }
22412
22413    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22414        self.read(cx).user_store().read(cx).participant_indices()
22415    }
22416
22417    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22418        let this = self.read(cx);
22419        let user_ids = this.collaborators().values().map(|c| c.user_id);
22420        this.user_store().read(cx).participant_names(user_ids, cx)
22421    }
22422}
22423
22424pub trait SemanticsProvider {
22425    fn hover(
22426        &self,
22427        buffer: &Entity<Buffer>,
22428        position: text::Anchor,
22429        cx: &mut App,
22430    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22431
22432    fn inline_values(
22433        &self,
22434        buffer_handle: Entity<Buffer>,
22435        range: Range<text::Anchor>,
22436        cx: &mut App,
22437    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22438
22439    fn inlay_hints(
22440        &self,
22441        buffer_handle: Entity<Buffer>,
22442        range: Range<text::Anchor>,
22443        cx: &mut App,
22444    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22445
22446    fn resolve_inlay_hint(
22447        &self,
22448        hint: InlayHint,
22449        buffer_handle: Entity<Buffer>,
22450        server_id: LanguageServerId,
22451        cx: &mut App,
22452    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22453
22454    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22455
22456    fn document_highlights(
22457        &self,
22458        buffer: &Entity<Buffer>,
22459        position: text::Anchor,
22460        cx: &mut App,
22461    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22462
22463    fn definitions(
22464        &self,
22465        buffer: &Entity<Buffer>,
22466        position: text::Anchor,
22467        kind: GotoDefinitionKind,
22468        cx: &mut App,
22469    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22470
22471    fn range_for_rename(
22472        &self,
22473        buffer: &Entity<Buffer>,
22474        position: text::Anchor,
22475        cx: &mut App,
22476    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22477
22478    fn perform_rename(
22479        &self,
22480        buffer: &Entity<Buffer>,
22481        position: text::Anchor,
22482        new_name: String,
22483        cx: &mut App,
22484    ) -> Option<Task<Result<ProjectTransaction>>>;
22485}
22486
22487pub trait CompletionProvider {
22488    fn completions(
22489        &self,
22490        excerpt_id: ExcerptId,
22491        buffer: &Entity<Buffer>,
22492        buffer_position: text::Anchor,
22493        trigger: CompletionContext,
22494        window: &mut Window,
22495        cx: &mut Context<Editor>,
22496    ) -> Task<Result<Vec<CompletionResponse>>>;
22497
22498    fn resolve_completions(
22499        &self,
22500        _buffer: Entity<Buffer>,
22501        _completion_indices: Vec<usize>,
22502        _completions: Rc<RefCell<Box<[Completion]>>>,
22503        _cx: &mut Context<Editor>,
22504    ) -> Task<Result<bool>> {
22505        Task::ready(Ok(false))
22506    }
22507
22508    fn apply_additional_edits_for_completion(
22509        &self,
22510        _buffer: Entity<Buffer>,
22511        _completions: Rc<RefCell<Box<[Completion]>>>,
22512        _completion_index: usize,
22513        _push_to_history: bool,
22514        _cx: &mut Context<Editor>,
22515    ) -> Task<Result<Option<language::Transaction>>> {
22516        Task::ready(Ok(None))
22517    }
22518
22519    fn is_completion_trigger(
22520        &self,
22521        buffer: &Entity<Buffer>,
22522        position: language::Anchor,
22523        text: &str,
22524        trigger_in_words: bool,
22525        menu_is_open: bool,
22526        cx: &mut Context<Editor>,
22527    ) -> bool;
22528
22529    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22530
22531    fn sort_completions(&self) -> bool {
22532        true
22533    }
22534
22535    fn filter_completions(&self) -> bool {
22536        true
22537    }
22538}
22539
22540pub trait CodeActionProvider {
22541    fn id(&self) -> Arc<str>;
22542
22543    fn code_actions(
22544        &self,
22545        buffer: &Entity<Buffer>,
22546        range: Range<text::Anchor>,
22547        window: &mut Window,
22548        cx: &mut App,
22549    ) -> Task<Result<Vec<CodeAction>>>;
22550
22551    fn apply_code_action(
22552        &self,
22553        buffer_handle: Entity<Buffer>,
22554        action: CodeAction,
22555        excerpt_id: ExcerptId,
22556        push_to_history: bool,
22557        window: &mut Window,
22558        cx: &mut App,
22559    ) -> Task<Result<ProjectTransaction>>;
22560}
22561
22562impl CodeActionProvider for Entity<Project> {
22563    fn id(&self) -> Arc<str> {
22564        "project".into()
22565    }
22566
22567    fn code_actions(
22568        &self,
22569        buffer: &Entity<Buffer>,
22570        range: Range<text::Anchor>,
22571        _window: &mut Window,
22572        cx: &mut App,
22573    ) -> Task<Result<Vec<CodeAction>>> {
22574        self.update(cx, |project, cx| {
22575            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22576            let code_actions = project.code_actions(buffer, range, None, cx);
22577            cx.background_spawn(async move {
22578                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22579                Ok(code_lens_actions
22580                    .context("code lens fetch")?
22581                    .into_iter()
22582                    .flatten()
22583                    .chain(
22584                        code_actions
22585                            .context("code action fetch")?
22586                            .into_iter()
22587                            .flatten(),
22588                    )
22589                    .collect())
22590            })
22591        })
22592    }
22593
22594    fn apply_code_action(
22595        &self,
22596        buffer_handle: Entity<Buffer>,
22597        action: CodeAction,
22598        _excerpt_id: ExcerptId,
22599        push_to_history: bool,
22600        _window: &mut Window,
22601        cx: &mut App,
22602    ) -> Task<Result<ProjectTransaction>> {
22603        self.update(cx, |project, cx| {
22604            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22605        })
22606    }
22607}
22608
22609fn snippet_completions(
22610    project: &Project,
22611    buffer: &Entity<Buffer>,
22612    buffer_position: text::Anchor,
22613    cx: &mut App,
22614) -> Task<Result<CompletionResponse>> {
22615    let languages = buffer.read(cx).languages_at(buffer_position);
22616    let snippet_store = project.snippets().read(cx);
22617
22618    let scopes: Vec<_> = languages
22619        .iter()
22620        .filter_map(|language| {
22621            let language_name = language.lsp_id();
22622            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22623
22624            if snippets.is_empty() {
22625                None
22626            } else {
22627                Some((language.default_scope(), snippets))
22628            }
22629        })
22630        .collect();
22631
22632    if scopes.is_empty() {
22633        return Task::ready(Ok(CompletionResponse {
22634            completions: vec![],
22635            display_options: CompletionDisplayOptions::default(),
22636            is_incomplete: false,
22637        }));
22638    }
22639
22640    let snapshot = buffer.read(cx).text_snapshot();
22641    let chars: String = snapshot
22642        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22643        .collect();
22644    let executor = cx.background_executor().clone();
22645
22646    cx.background_spawn(async move {
22647        let mut is_incomplete = false;
22648        let mut completions: Vec<Completion> = Vec::new();
22649        for (scope, snippets) in scopes.into_iter() {
22650            let classifier =
22651                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22652            let mut last_word = chars
22653                .chars()
22654                .take_while(|c| classifier.is_word(*c))
22655                .collect::<String>();
22656            last_word = last_word.chars().rev().collect();
22657
22658            if last_word.is_empty() {
22659                return Ok(CompletionResponse {
22660                    completions: vec![],
22661                    display_options: CompletionDisplayOptions::default(),
22662                    is_incomplete: true,
22663                });
22664            }
22665
22666            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22667            let to_lsp = |point: &text::Anchor| {
22668                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22669                point_to_lsp(end)
22670            };
22671            let lsp_end = to_lsp(&buffer_position);
22672
22673            let candidates = snippets
22674                .iter()
22675                .enumerate()
22676                .flat_map(|(ix, snippet)| {
22677                    snippet
22678                        .prefix
22679                        .iter()
22680                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22681                })
22682                .collect::<Vec<StringMatchCandidate>>();
22683
22684            const MAX_RESULTS: usize = 100;
22685            let mut matches = fuzzy::match_strings(
22686                &candidates,
22687                &last_word,
22688                last_word.chars().any(|c| c.is_uppercase()),
22689                true,
22690                MAX_RESULTS,
22691                &Default::default(),
22692                executor.clone(),
22693            )
22694            .await;
22695
22696            if matches.len() >= MAX_RESULTS {
22697                is_incomplete = true;
22698            }
22699
22700            // Remove all candidates where the query's start does not match the start of any word in the candidate
22701            if let Some(query_start) = last_word.chars().next() {
22702                matches.retain(|string_match| {
22703                    split_words(&string_match.string).any(|word| {
22704                        // Check that the first codepoint of the word as lowercase matches the first
22705                        // codepoint of the query as lowercase
22706                        word.chars()
22707                            .flat_map(|codepoint| codepoint.to_lowercase())
22708                            .zip(query_start.to_lowercase())
22709                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22710                    })
22711                });
22712            }
22713
22714            let matched_strings = matches
22715                .into_iter()
22716                .map(|m| m.string)
22717                .collect::<HashSet<_>>();
22718
22719            completions.extend(snippets.iter().filter_map(|snippet| {
22720                let matching_prefix = snippet
22721                    .prefix
22722                    .iter()
22723                    .find(|prefix| matched_strings.contains(*prefix))?;
22724                let start = as_offset - last_word.len();
22725                let start = snapshot.anchor_before(start);
22726                let range = start..buffer_position;
22727                let lsp_start = to_lsp(&start);
22728                let lsp_range = lsp::Range {
22729                    start: lsp_start,
22730                    end: lsp_end,
22731                };
22732                Some(Completion {
22733                    replace_range: range,
22734                    new_text: snippet.body.clone(),
22735                    source: CompletionSource::Lsp {
22736                        insert_range: None,
22737                        server_id: LanguageServerId(usize::MAX),
22738                        resolved: true,
22739                        lsp_completion: Box::new(lsp::CompletionItem {
22740                            label: snippet.prefix.first().unwrap().clone(),
22741                            kind: Some(CompletionItemKind::SNIPPET),
22742                            label_details: snippet.description.as_ref().map(|description| {
22743                                lsp::CompletionItemLabelDetails {
22744                                    detail: Some(description.clone()),
22745                                    description: None,
22746                                }
22747                            }),
22748                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22749                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22750                                lsp::InsertReplaceEdit {
22751                                    new_text: snippet.body.clone(),
22752                                    insert: lsp_range,
22753                                    replace: lsp_range,
22754                                },
22755                            )),
22756                            filter_text: Some(snippet.body.clone()),
22757                            sort_text: Some(char::MAX.to_string()),
22758                            ..lsp::CompletionItem::default()
22759                        }),
22760                        lsp_defaults: None,
22761                    },
22762                    label: CodeLabel {
22763                        text: matching_prefix.clone(),
22764                        runs: Vec::new(),
22765                        filter_range: 0..matching_prefix.len(),
22766                    },
22767                    icon_path: None,
22768                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22769                        single_line: snippet.name.clone().into(),
22770                        plain_text: snippet
22771                            .description
22772                            .clone()
22773                            .map(|description| description.into()),
22774                    }),
22775                    insert_text_mode: None,
22776                    confirm: None,
22777                })
22778            }))
22779        }
22780
22781        Ok(CompletionResponse {
22782            completions,
22783            display_options: CompletionDisplayOptions::default(),
22784            is_incomplete,
22785        })
22786    })
22787}
22788
22789impl CompletionProvider for Entity<Project> {
22790    fn completions(
22791        &self,
22792        _excerpt_id: ExcerptId,
22793        buffer: &Entity<Buffer>,
22794        buffer_position: text::Anchor,
22795        options: CompletionContext,
22796        _window: &mut Window,
22797        cx: &mut Context<Editor>,
22798    ) -> Task<Result<Vec<CompletionResponse>>> {
22799        self.update(cx, |project, cx| {
22800            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22801            let project_completions = project.completions(buffer, buffer_position, options, cx);
22802            cx.background_spawn(async move {
22803                let mut responses = project_completions.await?;
22804                let snippets = snippets.await?;
22805                if !snippets.completions.is_empty() {
22806                    responses.push(snippets);
22807                }
22808                Ok(responses)
22809            })
22810        })
22811    }
22812
22813    fn resolve_completions(
22814        &self,
22815        buffer: Entity<Buffer>,
22816        completion_indices: Vec<usize>,
22817        completions: Rc<RefCell<Box<[Completion]>>>,
22818        cx: &mut Context<Editor>,
22819    ) -> Task<Result<bool>> {
22820        self.update(cx, |project, cx| {
22821            project.lsp_store().update(cx, |lsp_store, cx| {
22822                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22823            })
22824        })
22825    }
22826
22827    fn apply_additional_edits_for_completion(
22828        &self,
22829        buffer: Entity<Buffer>,
22830        completions: Rc<RefCell<Box<[Completion]>>>,
22831        completion_index: usize,
22832        push_to_history: bool,
22833        cx: &mut Context<Editor>,
22834    ) -> Task<Result<Option<language::Transaction>>> {
22835        self.update(cx, |project, cx| {
22836            project.lsp_store().update(cx, |lsp_store, cx| {
22837                lsp_store.apply_additional_edits_for_completion(
22838                    buffer,
22839                    completions,
22840                    completion_index,
22841                    push_to_history,
22842                    cx,
22843                )
22844            })
22845        })
22846    }
22847
22848    fn is_completion_trigger(
22849        &self,
22850        buffer: &Entity<Buffer>,
22851        position: language::Anchor,
22852        text: &str,
22853        trigger_in_words: bool,
22854        menu_is_open: bool,
22855        cx: &mut Context<Editor>,
22856    ) -> bool {
22857        let mut chars = text.chars();
22858        let char = if let Some(char) = chars.next() {
22859            char
22860        } else {
22861            return false;
22862        };
22863        if chars.next().is_some() {
22864            return false;
22865        }
22866
22867        let buffer = buffer.read(cx);
22868        let snapshot = buffer.snapshot();
22869        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22870            return false;
22871        }
22872        let classifier = snapshot
22873            .char_classifier_at(position)
22874            .scope_context(Some(CharScopeContext::Completion));
22875        if trigger_in_words && classifier.is_word(char) {
22876            return true;
22877        }
22878
22879        buffer.completion_triggers().contains(text)
22880    }
22881}
22882
22883impl SemanticsProvider for Entity<Project> {
22884    fn hover(
22885        &self,
22886        buffer: &Entity<Buffer>,
22887        position: text::Anchor,
22888        cx: &mut App,
22889    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22890        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22891    }
22892
22893    fn document_highlights(
22894        &self,
22895        buffer: &Entity<Buffer>,
22896        position: text::Anchor,
22897        cx: &mut App,
22898    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22899        Some(self.update(cx, |project, cx| {
22900            project.document_highlights(buffer, position, cx)
22901        }))
22902    }
22903
22904    fn definitions(
22905        &self,
22906        buffer: &Entity<Buffer>,
22907        position: text::Anchor,
22908        kind: GotoDefinitionKind,
22909        cx: &mut App,
22910    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22911        Some(self.update(cx, |project, cx| match kind {
22912            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22913            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22914            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22915            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22916        }))
22917    }
22918
22919    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22920        self.update(cx, |project, cx| {
22921            if project
22922                .active_debug_session(cx)
22923                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22924            {
22925                return true;
22926            }
22927
22928            buffer.update(cx, |buffer, cx| {
22929                project.any_language_server_supports_inlay_hints(buffer, cx)
22930            })
22931        })
22932    }
22933
22934    fn inline_values(
22935        &self,
22936        buffer_handle: Entity<Buffer>,
22937        range: Range<text::Anchor>,
22938        cx: &mut App,
22939    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22940        self.update(cx, |project, cx| {
22941            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22942
22943            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22944        })
22945    }
22946
22947    fn inlay_hints(
22948        &self,
22949        buffer_handle: Entity<Buffer>,
22950        range: Range<text::Anchor>,
22951        cx: &mut App,
22952    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22953        Some(self.update(cx, |project, cx| {
22954            project.inlay_hints(buffer_handle, range, cx)
22955        }))
22956    }
22957
22958    fn resolve_inlay_hint(
22959        &self,
22960        hint: InlayHint,
22961        buffer_handle: Entity<Buffer>,
22962        server_id: LanguageServerId,
22963        cx: &mut App,
22964    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22965        Some(self.update(cx, |project, cx| {
22966            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22967        }))
22968    }
22969
22970    fn range_for_rename(
22971        &self,
22972        buffer: &Entity<Buffer>,
22973        position: text::Anchor,
22974        cx: &mut App,
22975    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22976        Some(self.update(cx, |project, cx| {
22977            let buffer = buffer.clone();
22978            let task = project.prepare_rename(buffer.clone(), position, cx);
22979            cx.spawn(async move |_, cx| {
22980                Ok(match task.await? {
22981                    PrepareRenameResponse::Success(range) => Some(range),
22982                    PrepareRenameResponse::InvalidPosition => None,
22983                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22984                        // Fallback on using TreeSitter info to determine identifier range
22985                        buffer.read_with(cx, |buffer, _| {
22986                            let snapshot = buffer.snapshot();
22987                            let (range, kind) = snapshot.surrounding_word(position, None);
22988                            if kind != Some(CharKind::Word) {
22989                                return None;
22990                            }
22991                            Some(
22992                                snapshot.anchor_before(range.start)
22993                                    ..snapshot.anchor_after(range.end),
22994                            )
22995                        })?
22996                    }
22997                })
22998            })
22999        }))
23000    }
23001
23002    fn perform_rename(
23003        &self,
23004        buffer: &Entity<Buffer>,
23005        position: text::Anchor,
23006        new_name: String,
23007        cx: &mut App,
23008    ) -> Option<Task<Result<ProjectTransaction>>> {
23009        Some(self.update(cx, |project, cx| {
23010            project.perform_rename(buffer.clone(), position, new_name, cx)
23011        }))
23012    }
23013}
23014
23015fn inlay_hint_settings(
23016    location: Anchor,
23017    snapshot: &MultiBufferSnapshot,
23018    cx: &mut Context<Editor>,
23019) -> InlayHintSettings {
23020    let file = snapshot.file_at(location);
23021    let language = snapshot.language_at(location).map(|l| l.name());
23022    language_settings(language, file, cx).inlay_hints
23023}
23024
23025fn consume_contiguous_rows(
23026    contiguous_row_selections: &mut Vec<Selection<Point>>,
23027    selection: &Selection<Point>,
23028    display_map: &DisplaySnapshot,
23029    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23030) -> (MultiBufferRow, MultiBufferRow) {
23031    contiguous_row_selections.push(selection.clone());
23032    let start_row = starting_row(selection, display_map);
23033    let mut end_row = ending_row(selection, display_map);
23034
23035    while let Some(next_selection) = selections.peek() {
23036        if next_selection.start.row <= end_row.0 {
23037            end_row = ending_row(next_selection, display_map);
23038            contiguous_row_selections.push(selections.next().unwrap().clone());
23039        } else {
23040            break;
23041        }
23042    }
23043    (start_row, end_row)
23044}
23045
23046fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23047    if selection.start.column > 0 {
23048        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23049    } else {
23050        MultiBufferRow(selection.start.row)
23051    }
23052}
23053
23054fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23055    if next_selection.end.column > 0 || next_selection.is_empty() {
23056        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23057    } else {
23058        MultiBufferRow(next_selection.end.row)
23059    }
23060}
23061
23062impl EditorSnapshot {
23063    pub fn remote_selections_in_range<'a>(
23064        &'a self,
23065        range: &'a Range<Anchor>,
23066        collaboration_hub: &dyn CollaborationHub,
23067        cx: &'a App,
23068    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23069        let participant_names = collaboration_hub.user_names(cx);
23070        let participant_indices = collaboration_hub.user_participant_indices(cx);
23071        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23072        let collaborators_by_replica_id = collaborators_by_peer_id
23073            .values()
23074            .map(|collaborator| (collaborator.replica_id, collaborator))
23075            .collect::<HashMap<_, _>>();
23076        self.buffer_snapshot
23077            .selections_in_range(range, false)
23078            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23079                if replica_id == AGENT_REPLICA_ID {
23080                    Some(RemoteSelection {
23081                        replica_id,
23082                        selection,
23083                        cursor_shape,
23084                        line_mode,
23085                        collaborator_id: CollaboratorId::Agent,
23086                        user_name: Some("Agent".into()),
23087                        color: cx.theme().players().agent(),
23088                    })
23089                } else {
23090                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23091                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23092                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23093                    Some(RemoteSelection {
23094                        replica_id,
23095                        selection,
23096                        cursor_shape,
23097                        line_mode,
23098                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23099                        user_name,
23100                        color: if let Some(index) = participant_index {
23101                            cx.theme().players().color_for_participant(index.0)
23102                        } else {
23103                            cx.theme().players().absent()
23104                        },
23105                    })
23106                }
23107            })
23108    }
23109
23110    pub fn hunks_for_ranges(
23111        &self,
23112        ranges: impl IntoIterator<Item = Range<Point>>,
23113    ) -> Vec<MultiBufferDiffHunk> {
23114        let mut hunks = Vec::new();
23115        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23116            HashMap::default();
23117        for query_range in ranges {
23118            let query_rows =
23119                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23120            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23121                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23122            ) {
23123                // Include deleted hunks that are adjacent to the query range, because
23124                // otherwise they would be missed.
23125                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23126                if hunk.status().is_deleted() {
23127                    intersects_range |= hunk.row_range.start == query_rows.end;
23128                    intersects_range |= hunk.row_range.end == query_rows.start;
23129                }
23130                if intersects_range {
23131                    if !processed_buffer_rows
23132                        .entry(hunk.buffer_id)
23133                        .or_default()
23134                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23135                    {
23136                        continue;
23137                    }
23138                    hunks.push(hunk);
23139                }
23140            }
23141        }
23142
23143        hunks
23144    }
23145
23146    fn display_diff_hunks_for_rows<'a>(
23147        &'a self,
23148        display_rows: Range<DisplayRow>,
23149        folded_buffers: &'a HashSet<BufferId>,
23150    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23151        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23152        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23153
23154        self.buffer_snapshot
23155            .diff_hunks_in_range(buffer_start..buffer_end)
23156            .filter_map(|hunk| {
23157                if folded_buffers.contains(&hunk.buffer_id) {
23158                    return None;
23159                }
23160
23161                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23162                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23163
23164                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23165                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23166
23167                let display_hunk = if hunk_display_start.column() != 0 {
23168                    DisplayDiffHunk::Folded {
23169                        display_row: hunk_display_start.row(),
23170                    }
23171                } else {
23172                    let mut end_row = hunk_display_end.row();
23173                    if hunk_display_end.column() > 0 {
23174                        end_row.0 += 1;
23175                    }
23176                    let is_created_file = hunk.is_created_file();
23177                    DisplayDiffHunk::Unfolded {
23178                        status: hunk.status(),
23179                        diff_base_byte_range: hunk.diff_base_byte_range,
23180                        display_row_range: hunk_display_start.row()..end_row,
23181                        multi_buffer_range: Anchor::range_in_buffer(
23182                            hunk.excerpt_id,
23183                            hunk.buffer_id,
23184                            hunk.buffer_range,
23185                        ),
23186                        is_created_file,
23187                    }
23188                };
23189
23190                Some(display_hunk)
23191            })
23192    }
23193
23194    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23195        self.display_snapshot.buffer_snapshot.language_at(position)
23196    }
23197
23198    pub fn is_focused(&self) -> bool {
23199        self.is_focused
23200    }
23201
23202    pub fn placeholder_text(&self) -> Option<String> {
23203        self.placeholder_display_snapshot
23204            .as_ref()
23205            .map(|display_map| display_map.text())
23206    }
23207
23208    pub fn scroll_position(&self) -> gpui::Point<f32> {
23209        self.scroll_anchor.scroll_position(&self.display_snapshot)
23210    }
23211
23212    fn gutter_dimensions(
23213        &self,
23214        font_id: FontId,
23215        font_size: Pixels,
23216        max_line_number_width: Pixels,
23217        cx: &App,
23218    ) -> Option<GutterDimensions> {
23219        if !self.show_gutter {
23220            return None;
23221        }
23222
23223        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23224        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23225
23226        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23227            matches!(
23228                ProjectSettings::get_global(cx).git.git_gutter,
23229                GitGutterSetting::TrackedFiles
23230            )
23231        });
23232        let gutter_settings = EditorSettings::get_global(cx).gutter;
23233        let show_line_numbers = self
23234            .show_line_numbers
23235            .unwrap_or(gutter_settings.line_numbers);
23236        let line_gutter_width = if show_line_numbers {
23237            // Avoid flicker-like gutter resizes when the line number gains another digit by
23238            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23239            let min_width_for_number_on_gutter =
23240                ch_advance * gutter_settings.min_line_number_digits as f32;
23241            max_line_number_width.max(min_width_for_number_on_gutter)
23242        } else {
23243            0.0.into()
23244        };
23245
23246        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23247        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23248
23249        let git_blame_entries_width =
23250            self.git_blame_gutter_max_author_length
23251                .map(|max_author_length| {
23252                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23253                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23254
23255                    /// The number of characters to dedicate to gaps and margins.
23256                    const SPACING_WIDTH: usize = 4;
23257
23258                    let max_char_count = max_author_length.min(renderer.max_author_length())
23259                        + ::git::SHORT_SHA_LENGTH
23260                        + MAX_RELATIVE_TIMESTAMP.len()
23261                        + SPACING_WIDTH;
23262
23263                    ch_advance * max_char_count
23264                });
23265
23266        let is_singleton = self.buffer_snapshot.is_singleton();
23267
23268        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23269        left_padding += if !is_singleton {
23270            ch_width * 4.0
23271        } else if show_runnables || show_breakpoints {
23272            ch_width * 3.0
23273        } else if show_git_gutter && show_line_numbers {
23274            ch_width * 2.0
23275        } else if show_git_gutter || show_line_numbers {
23276            ch_width
23277        } else {
23278            px(0.)
23279        };
23280
23281        let shows_folds = is_singleton && gutter_settings.folds;
23282
23283        let right_padding = if shows_folds && show_line_numbers {
23284            ch_width * 4.0
23285        } else if shows_folds || (!is_singleton && show_line_numbers) {
23286            ch_width * 3.0
23287        } else if show_line_numbers {
23288            ch_width
23289        } else {
23290            px(0.)
23291        };
23292
23293        Some(GutterDimensions {
23294            left_padding,
23295            right_padding,
23296            width: line_gutter_width + left_padding + right_padding,
23297            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23298            git_blame_entries_width,
23299        })
23300    }
23301
23302    pub fn render_crease_toggle(
23303        &self,
23304        buffer_row: MultiBufferRow,
23305        row_contains_cursor: bool,
23306        editor: Entity<Editor>,
23307        window: &mut Window,
23308        cx: &mut App,
23309    ) -> Option<AnyElement> {
23310        let folded = self.is_line_folded(buffer_row);
23311        let mut is_foldable = false;
23312
23313        if let Some(crease) = self
23314            .crease_snapshot
23315            .query_row(buffer_row, &self.buffer_snapshot)
23316        {
23317            is_foldable = true;
23318            match crease {
23319                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23320                    if let Some(render_toggle) = render_toggle {
23321                        let toggle_callback =
23322                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23323                                if folded {
23324                                    editor.update(cx, |editor, cx| {
23325                                        editor.fold_at(buffer_row, window, cx)
23326                                    });
23327                                } else {
23328                                    editor.update(cx, |editor, cx| {
23329                                        editor.unfold_at(buffer_row, window, cx)
23330                                    });
23331                                }
23332                            });
23333                        return Some((render_toggle)(
23334                            buffer_row,
23335                            folded,
23336                            toggle_callback,
23337                            window,
23338                            cx,
23339                        ));
23340                    }
23341                }
23342            }
23343        }
23344
23345        is_foldable |= self.starts_indent(buffer_row);
23346
23347        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23348            Some(
23349                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23350                    .toggle_state(folded)
23351                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23352                        if folded {
23353                            this.unfold_at(buffer_row, window, cx);
23354                        } else {
23355                            this.fold_at(buffer_row, window, cx);
23356                        }
23357                    }))
23358                    .into_any_element(),
23359            )
23360        } else {
23361            None
23362        }
23363    }
23364
23365    pub fn render_crease_trailer(
23366        &self,
23367        buffer_row: MultiBufferRow,
23368        window: &mut Window,
23369        cx: &mut App,
23370    ) -> Option<AnyElement> {
23371        let folded = self.is_line_folded(buffer_row);
23372        if let Crease::Inline { render_trailer, .. } = self
23373            .crease_snapshot
23374            .query_row(buffer_row, &self.buffer_snapshot)?
23375        {
23376            let render_trailer = render_trailer.as_ref()?;
23377            Some(render_trailer(buffer_row, folded, window, cx))
23378        } else {
23379            None
23380        }
23381    }
23382}
23383
23384impl Deref for EditorSnapshot {
23385    type Target = DisplaySnapshot;
23386
23387    fn deref(&self) -> &Self::Target {
23388        &self.display_snapshot
23389    }
23390}
23391
23392#[derive(Clone, Debug, PartialEq, Eq)]
23393pub enum EditorEvent {
23394    InputIgnored {
23395        text: Arc<str>,
23396    },
23397    InputHandled {
23398        utf16_range_to_replace: Option<Range<isize>>,
23399        text: Arc<str>,
23400    },
23401    ExcerptsAdded {
23402        buffer: Entity<Buffer>,
23403        predecessor: ExcerptId,
23404        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23405    },
23406    ExcerptsRemoved {
23407        ids: Vec<ExcerptId>,
23408        removed_buffer_ids: Vec<BufferId>,
23409    },
23410    BufferFoldToggled {
23411        ids: Vec<ExcerptId>,
23412        folded: bool,
23413    },
23414    ExcerptsEdited {
23415        ids: Vec<ExcerptId>,
23416    },
23417    ExcerptsExpanded {
23418        ids: Vec<ExcerptId>,
23419    },
23420    BufferEdited,
23421    Edited {
23422        transaction_id: clock::Lamport,
23423    },
23424    Reparsed(BufferId),
23425    Focused,
23426    FocusedIn,
23427    Blurred,
23428    DirtyChanged,
23429    Saved,
23430    TitleChanged,
23431    SelectionsChanged {
23432        local: bool,
23433    },
23434    ScrollPositionChanged {
23435        local: bool,
23436        autoscroll: bool,
23437    },
23438    TransactionUndone {
23439        transaction_id: clock::Lamport,
23440    },
23441    TransactionBegun {
23442        transaction_id: clock::Lamport,
23443    },
23444    CursorShapeChanged,
23445    BreadcrumbsChanged,
23446    PushedToNavHistory {
23447        anchor: Anchor,
23448        is_deactivate: bool,
23449    },
23450}
23451
23452impl EventEmitter<EditorEvent> for Editor {}
23453
23454impl Focusable for Editor {
23455    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23456        self.focus_handle.clone()
23457    }
23458}
23459
23460impl Render for Editor {
23461    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23462        let settings = ThemeSettings::get_global(cx);
23463
23464        let mut text_style = match self.mode {
23465            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23466                color: cx.theme().colors().editor_foreground,
23467                font_family: settings.ui_font.family.clone(),
23468                font_features: settings.ui_font.features.clone(),
23469                font_fallbacks: settings.ui_font.fallbacks.clone(),
23470                font_size: rems(0.875).into(),
23471                font_weight: settings.ui_font.weight,
23472                line_height: relative(settings.buffer_line_height.value()),
23473                ..Default::default()
23474            },
23475            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23476                color: cx.theme().colors().editor_foreground,
23477                font_family: settings.buffer_font.family.clone(),
23478                font_features: settings.buffer_font.features.clone(),
23479                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23480                font_size: settings.buffer_font_size(cx).into(),
23481                font_weight: settings.buffer_font.weight,
23482                line_height: relative(settings.buffer_line_height.value()),
23483                ..Default::default()
23484            },
23485        };
23486        if let Some(text_style_refinement) = &self.text_style_refinement {
23487            text_style.refine(text_style_refinement)
23488        }
23489
23490        let background = match self.mode {
23491            EditorMode::SingleLine => cx.theme().system().transparent,
23492            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23493            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23494            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23495        };
23496
23497        EditorElement::new(
23498            &cx.entity(),
23499            EditorStyle {
23500                background,
23501                border: cx.theme().colors().border,
23502                local_player: cx.theme().players().local(),
23503                text: text_style,
23504                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23505                syntax: cx.theme().syntax().clone(),
23506                status: cx.theme().status().clone(),
23507                inlay_hints_style: make_inlay_hints_style(cx),
23508                edit_prediction_styles: make_suggestion_styles(cx),
23509                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23510                show_underlines: self.diagnostics_enabled(),
23511            },
23512        )
23513    }
23514}
23515
23516impl EntityInputHandler for Editor {
23517    fn text_for_range(
23518        &mut self,
23519        range_utf16: Range<usize>,
23520        adjusted_range: &mut Option<Range<usize>>,
23521        _: &mut Window,
23522        cx: &mut Context<Self>,
23523    ) -> Option<String> {
23524        let snapshot = self.buffer.read(cx).read(cx);
23525        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23526        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23527        if (start.0..end.0) != range_utf16 {
23528            adjusted_range.replace(start.0..end.0);
23529        }
23530        Some(snapshot.text_for_range(start..end).collect())
23531    }
23532
23533    fn selected_text_range(
23534        &mut self,
23535        ignore_disabled_input: bool,
23536        _: &mut Window,
23537        cx: &mut Context<Self>,
23538    ) -> Option<UTF16Selection> {
23539        // Prevent the IME menu from appearing when holding down an alphabetic key
23540        // while input is disabled.
23541        if !ignore_disabled_input && !self.input_enabled {
23542            return None;
23543        }
23544
23545        let selection = self.selections.newest::<OffsetUtf16>(cx);
23546        let range = selection.range();
23547
23548        Some(UTF16Selection {
23549            range: range.start.0..range.end.0,
23550            reversed: selection.reversed,
23551        })
23552    }
23553
23554    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23555        let snapshot = self.buffer.read(cx).read(cx);
23556        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23557        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23558    }
23559
23560    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23561        self.clear_highlights::<InputComposition>(cx);
23562        self.ime_transaction.take();
23563    }
23564
23565    fn replace_text_in_range(
23566        &mut self,
23567        range_utf16: Option<Range<usize>>,
23568        text: &str,
23569        window: &mut Window,
23570        cx: &mut Context<Self>,
23571    ) {
23572        if !self.input_enabled {
23573            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23574            return;
23575        }
23576
23577        self.transact(window, cx, |this, window, cx| {
23578            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23579                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23580                Some(this.selection_replacement_ranges(range_utf16, cx))
23581            } else {
23582                this.marked_text_ranges(cx)
23583            };
23584
23585            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23586                let newest_selection_id = this.selections.newest_anchor().id;
23587                this.selections
23588                    .all::<OffsetUtf16>(cx)
23589                    .iter()
23590                    .zip(ranges_to_replace.iter())
23591                    .find_map(|(selection, range)| {
23592                        if selection.id == newest_selection_id {
23593                            Some(
23594                                (range.start.0 as isize - selection.head().0 as isize)
23595                                    ..(range.end.0 as isize - selection.head().0 as isize),
23596                            )
23597                        } else {
23598                            None
23599                        }
23600                    })
23601            });
23602
23603            cx.emit(EditorEvent::InputHandled {
23604                utf16_range_to_replace: range_to_replace,
23605                text: text.into(),
23606            });
23607
23608            if let Some(new_selected_ranges) = new_selected_ranges {
23609                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23610                    selections.select_ranges(new_selected_ranges)
23611                });
23612                this.backspace(&Default::default(), window, cx);
23613            }
23614
23615            this.handle_input(text, window, cx);
23616        });
23617
23618        if let Some(transaction) = self.ime_transaction {
23619            self.buffer.update(cx, |buffer, cx| {
23620                buffer.group_until_transaction(transaction, cx);
23621            });
23622        }
23623
23624        self.unmark_text(window, cx);
23625    }
23626
23627    fn replace_and_mark_text_in_range(
23628        &mut self,
23629        range_utf16: Option<Range<usize>>,
23630        text: &str,
23631        new_selected_range_utf16: Option<Range<usize>>,
23632        window: &mut Window,
23633        cx: &mut Context<Self>,
23634    ) {
23635        if !self.input_enabled {
23636            return;
23637        }
23638
23639        let transaction = self.transact(window, cx, |this, window, cx| {
23640            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23641                let snapshot = this.buffer.read(cx).read(cx);
23642                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23643                    for marked_range in &mut marked_ranges {
23644                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23645                        marked_range.start.0 += relative_range_utf16.start;
23646                        marked_range.start =
23647                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23648                        marked_range.end =
23649                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23650                    }
23651                }
23652                Some(marked_ranges)
23653            } else if let Some(range_utf16) = range_utf16 {
23654                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23655                Some(this.selection_replacement_ranges(range_utf16, cx))
23656            } else {
23657                None
23658            };
23659
23660            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23661                let newest_selection_id = this.selections.newest_anchor().id;
23662                this.selections
23663                    .all::<OffsetUtf16>(cx)
23664                    .iter()
23665                    .zip(ranges_to_replace.iter())
23666                    .find_map(|(selection, range)| {
23667                        if selection.id == newest_selection_id {
23668                            Some(
23669                                (range.start.0 as isize - selection.head().0 as isize)
23670                                    ..(range.end.0 as isize - selection.head().0 as isize),
23671                            )
23672                        } else {
23673                            None
23674                        }
23675                    })
23676            });
23677
23678            cx.emit(EditorEvent::InputHandled {
23679                utf16_range_to_replace: range_to_replace,
23680                text: text.into(),
23681            });
23682
23683            if let Some(ranges) = ranges_to_replace {
23684                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23685                    s.select_ranges(ranges)
23686                });
23687            }
23688
23689            let marked_ranges = {
23690                let snapshot = this.buffer.read(cx).read(cx);
23691                this.selections
23692                    .disjoint_anchors_arc()
23693                    .iter()
23694                    .map(|selection| {
23695                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23696                    })
23697                    .collect::<Vec<_>>()
23698            };
23699
23700            if text.is_empty() {
23701                this.unmark_text(window, cx);
23702            } else {
23703                this.highlight_text::<InputComposition>(
23704                    marked_ranges.clone(),
23705                    HighlightStyle {
23706                        underline: Some(UnderlineStyle {
23707                            thickness: px(1.),
23708                            color: None,
23709                            wavy: false,
23710                        }),
23711                        ..Default::default()
23712                    },
23713                    cx,
23714                );
23715            }
23716
23717            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23718            let use_autoclose = this.use_autoclose;
23719            let use_auto_surround = this.use_auto_surround;
23720            this.set_use_autoclose(false);
23721            this.set_use_auto_surround(false);
23722            this.handle_input(text, window, cx);
23723            this.set_use_autoclose(use_autoclose);
23724            this.set_use_auto_surround(use_auto_surround);
23725
23726            if let Some(new_selected_range) = new_selected_range_utf16 {
23727                let snapshot = this.buffer.read(cx).read(cx);
23728                let new_selected_ranges = marked_ranges
23729                    .into_iter()
23730                    .map(|marked_range| {
23731                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23732                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23733                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23734                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23735                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23736                    })
23737                    .collect::<Vec<_>>();
23738
23739                drop(snapshot);
23740                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23741                    selections.select_ranges(new_selected_ranges)
23742                });
23743            }
23744        });
23745
23746        self.ime_transaction = self.ime_transaction.or(transaction);
23747        if let Some(transaction) = self.ime_transaction {
23748            self.buffer.update(cx, |buffer, cx| {
23749                buffer.group_until_transaction(transaction, cx);
23750            });
23751        }
23752
23753        if self.text_highlights::<InputComposition>(cx).is_none() {
23754            self.ime_transaction.take();
23755        }
23756    }
23757
23758    fn bounds_for_range(
23759        &mut self,
23760        range_utf16: Range<usize>,
23761        element_bounds: gpui::Bounds<Pixels>,
23762        window: &mut Window,
23763        cx: &mut Context<Self>,
23764    ) -> Option<gpui::Bounds<Pixels>> {
23765        let text_layout_details = self.text_layout_details(window);
23766        let CharacterDimensions {
23767            em_width,
23768            em_advance,
23769            line_height,
23770        } = self.character_dimensions(window);
23771
23772        let snapshot = self.snapshot(window, cx);
23773        let scroll_position = snapshot.scroll_position();
23774        let scroll_left = scroll_position.x * em_advance;
23775
23776        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23777        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23778            + self.gutter_dimensions.full_width();
23779        let y = line_height * (start.row().as_f32() - scroll_position.y);
23780
23781        Some(Bounds {
23782            origin: element_bounds.origin + point(x, y),
23783            size: size(em_width, line_height),
23784        })
23785    }
23786
23787    fn character_index_for_point(
23788        &mut self,
23789        point: gpui::Point<Pixels>,
23790        _window: &mut Window,
23791        _cx: &mut Context<Self>,
23792    ) -> Option<usize> {
23793        let position_map = self.last_position_map.as_ref()?;
23794        if !position_map.text_hitbox.contains(&point) {
23795            return None;
23796        }
23797        let display_point = position_map.point_for_position(point).previous_valid;
23798        let anchor = position_map
23799            .snapshot
23800            .display_point_to_anchor(display_point, Bias::Left);
23801        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23802        Some(utf16_offset.0)
23803    }
23804}
23805
23806trait SelectionExt {
23807    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23808    fn spanned_rows(
23809        &self,
23810        include_end_if_at_line_start: bool,
23811        map: &DisplaySnapshot,
23812    ) -> Range<MultiBufferRow>;
23813}
23814
23815impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23816    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23817        let start = self
23818            .start
23819            .to_point(&map.buffer_snapshot)
23820            .to_display_point(map);
23821        let end = self
23822            .end
23823            .to_point(&map.buffer_snapshot)
23824            .to_display_point(map);
23825        if self.reversed {
23826            end..start
23827        } else {
23828            start..end
23829        }
23830    }
23831
23832    fn spanned_rows(
23833        &self,
23834        include_end_if_at_line_start: bool,
23835        map: &DisplaySnapshot,
23836    ) -> Range<MultiBufferRow> {
23837        let start = self.start.to_point(&map.buffer_snapshot);
23838        let mut end = self.end.to_point(&map.buffer_snapshot);
23839        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23840            end.row -= 1;
23841        }
23842
23843        let buffer_start = map.prev_line_boundary(start).0;
23844        let buffer_end = map.next_line_boundary(end).0;
23845        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23846    }
23847}
23848
23849impl<T: InvalidationRegion> InvalidationStack<T> {
23850    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23851    where
23852        S: Clone + ToOffset,
23853    {
23854        while let Some(region) = self.last() {
23855            let all_selections_inside_invalidation_ranges =
23856                if selections.len() == region.ranges().len() {
23857                    selections
23858                        .iter()
23859                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23860                        .all(|(selection, invalidation_range)| {
23861                            let head = selection.head().to_offset(buffer);
23862                            invalidation_range.start <= head && invalidation_range.end >= head
23863                        })
23864                } else {
23865                    false
23866                };
23867
23868            if all_selections_inside_invalidation_ranges {
23869                break;
23870            } else {
23871                self.pop();
23872            }
23873        }
23874    }
23875}
23876
23877impl<T> Default for InvalidationStack<T> {
23878    fn default() -> Self {
23879        Self(Default::default())
23880    }
23881}
23882
23883impl<T> Deref for InvalidationStack<T> {
23884    type Target = Vec<T>;
23885
23886    fn deref(&self) -> &Self::Target {
23887        &self.0
23888    }
23889}
23890
23891impl<T> DerefMut for InvalidationStack<T> {
23892    fn deref_mut(&mut self) -> &mut Self::Target {
23893        &mut self.0
23894    }
23895}
23896
23897impl InvalidationRegion for SnippetState {
23898    fn ranges(&self) -> &[Range<Anchor>] {
23899        &self.ranges[self.active_index]
23900    }
23901}
23902
23903fn edit_prediction_edit_text(
23904    current_snapshot: &BufferSnapshot,
23905    edits: &[(Range<Anchor>, String)],
23906    edit_preview: &EditPreview,
23907    include_deletions: bool,
23908    cx: &App,
23909) -> HighlightedText {
23910    let edits = edits
23911        .iter()
23912        .map(|(anchor, text)| {
23913            (
23914                anchor.start.text_anchor..anchor.end.text_anchor,
23915                text.clone(),
23916            )
23917        })
23918        .collect::<Vec<_>>();
23919
23920    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23921}
23922
23923fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23924    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23925    // Just show the raw edit text with basic styling
23926    let mut text = String::new();
23927    let mut highlights = Vec::new();
23928
23929    let insertion_highlight_style = HighlightStyle {
23930        color: Some(cx.theme().colors().text),
23931        ..Default::default()
23932    };
23933
23934    for (_, edit_text) in edits {
23935        let start_offset = text.len();
23936        text.push_str(edit_text);
23937        let end_offset = text.len();
23938
23939        if start_offset < end_offset {
23940            highlights.push((start_offset..end_offset, insertion_highlight_style));
23941        }
23942    }
23943
23944    HighlightedText {
23945        text: text.into(),
23946        highlights,
23947    }
23948}
23949
23950pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23951    match severity {
23952        lsp::DiagnosticSeverity::ERROR => colors.error,
23953        lsp::DiagnosticSeverity::WARNING => colors.warning,
23954        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23955        lsp::DiagnosticSeverity::HINT => colors.info,
23956        _ => colors.ignored,
23957    }
23958}
23959
23960pub fn styled_runs_for_code_label<'a>(
23961    label: &'a CodeLabel,
23962    syntax_theme: &'a theme::SyntaxTheme,
23963) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23964    let fade_out = HighlightStyle {
23965        fade_out: Some(0.35),
23966        ..Default::default()
23967    };
23968
23969    let mut prev_end = label.filter_range.end;
23970    label
23971        .runs
23972        .iter()
23973        .enumerate()
23974        .flat_map(move |(ix, (range, highlight_id))| {
23975            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23976                style
23977            } else {
23978                return Default::default();
23979            };
23980            let muted_style = style.highlight(fade_out);
23981
23982            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23983            if range.start >= label.filter_range.end {
23984                if range.start > prev_end {
23985                    runs.push((prev_end..range.start, fade_out));
23986                }
23987                runs.push((range.clone(), muted_style));
23988            } else if range.end <= label.filter_range.end {
23989                runs.push((range.clone(), style));
23990            } else {
23991                runs.push((range.start..label.filter_range.end, style));
23992                runs.push((label.filter_range.end..range.end, muted_style));
23993            }
23994            prev_end = cmp::max(prev_end, range.end);
23995
23996            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23997                runs.push((prev_end..label.text.len(), fade_out));
23998            }
23999
24000            runs
24001        })
24002}
24003
24004pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24005    let mut prev_index = 0;
24006    let mut prev_codepoint: Option<char> = None;
24007    text.char_indices()
24008        .chain([(text.len(), '\0')])
24009        .filter_map(move |(index, codepoint)| {
24010            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24011            let is_boundary = index == text.len()
24012                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24013                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24014            if is_boundary {
24015                let chunk = &text[prev_index..index];
24016                prev_index = index;
24017                Some(chunk)
24018            } else {
24019                None
24020            }
24021        })
24022}
24023
24024pub trait RangeToAnchorExt: Sized {
24025    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24026
24027    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24028        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
24029        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24030    }
24031}
24032
24033impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24034    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24035        let start_offset = self.start.to_offset(snapshot);
24036        let end_offset = self.end.to_offset(snapshot);
24037        if start_offset == end_offset {
24038            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24039        } else {
24040            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24041        }
24042    }
24043}
24044
24045pub trait RowExt {
24046    fn as_f32(&self) -> f32;
24047
24048    fn next_row(&self) -> Self;
24049
24050    fn previous_row(&self) -> Self;
24051
24052    fn minus(&self, other: Self) -> u32;
24053}
24054
24055impl RowExt for DisplayRow {
24056    fn as_f32(&self) -> f32 {
24057        self.0 as f32
24058    }
24059
24060    fn next_row(&self) -> Self {
24061        Self(self.0 + 1)
24062    }
24063
24064    fn previous_row(&self) -> Self {
24065        Self(self.0.saturating_sub(1))
24066    }
24067
24068    fn minus(&self, other: Self) -> u32 {
24069        self.0 - other.0
24070    }
24071}
24072
24073impl RowExt for MultiBufferRow {
24074    fn as_f32(&self) -> f32 {
24075        self.0 as f32
24076    }
24077
24078    fn next_row(&self) -> Self {
24079        Self(self.0 + 1)
24080    }
24081
24082    fn previous_row(&self) -> Self {
24083        Self(self.0.saturating_sub(1))
24084    }
24085
24086    fn minus(&self, other: Self) -> u32 {
24087        self.0 - other.0
24088    }
24089}
24090
24091trait RowRangeExt {
24092    type Row;
24093
24094    fn len(&self) -> usize;
24095
24096    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24097}
24098
24099impl RowRangeExt for Range<MultiBufferRow> {
24100    type Row = MultiBufferRow;
24101
24102    fn len(&self) -> usize {
24103        (self.end.0 - self.start.0) as usize
24104    }
24105
24106    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24107        (self.start.0..self.end.0).map(MultiBufferRow)
24108    }
24109}
24110
24111impl RowRangeExt for Range<DisplayRow> {
24112    type Row = DisplayRow;
24113
24114    fn len(&self) -> usize {
24115        (self.end.0 - self.start.0) as usize
24116    }
24117
24118    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24119        (self.start.0..self.end.0).map(DisplayRow)
24120    }
24121}
24122
24123/// If select range has more than one line, we
24124/// just point the cursor to range.start.
24125fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24126    if range.start.row == range.end.row {
24127        range
24128    } else {
24129        range.start..range.start
24130    }
24131}
24132pub struct KillRing(ClipboardItem);
24133impl Global for KillRing {}
24134
24135const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24136
24137enum BreakpointPromptEditAction {
24138    Log,
24139    Condition,
24140    HitCondition,
24141}
24142
24143struct BreakpointPromptEditor {
24144    pub(crate) prompt: Entity<Editor>,
24145    editor: WeakEntity<Editor>,
24146    breakpoint_anchor: Anchor,
24147    breakpoint: Breakpoint,
24148    edit_action: BreakpointPromptEditAction,
24149    block_ids: HashSet<CustomBlockId>,
24150    editor_margins: Arc<Mutex<EditorMargins>>,
24151    _subscriptions: Vec<Subscription>,
24152}
24153
24154impl BreakpointPromptEditor {
24155    const MAX_LINES: u8 = 4;
24156
24157    fn new(
24158        editor: WeakEntity<Editor>,
24159        breakpoint_anchor: Anchor,
24160        breakpoint: Breakpoint,
24161        edit_action: BreakpointPromptEditAction,
24162        window: &mut Window,
24163        cx: &mut Context<Self>,
24164    ) -> Self {
24165        let base_text = match edit_action {
24166            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24167            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24168            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24169        }
24170        .map(|msg| msg.to_string())
24171        .unwrap_or_default();
24172
24173        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24174        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24175
24176        let prompt = cx.new(|cx| {
24177            let mut prompt = Editor::new(
24178                EditorMode::AutoHeight {
24179                    min_lines: 1,
24180                    max_lines: Some(Self::MAX_LINES as usize),
24181                },
24182                buffer,
24183                None,
24184                window,
24185                cx,
24186            );
24187            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24188            prompt.set_show_cursor_when_unfocused(false, cx);
24189            prompt.set_placeholder_text(
24190                match edit_action {
24191                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24192                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24193                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24194                },
24195                window,
24196                cx,
24197            );
24198
24199            prompt
24200        });
24201
24202        Self {
24203            prompt,
24204            editor,
24205            breakpoint_anchor,
24206            breakpoint,
24207            edit_action,
24208            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24209            block_ids: Default::default(),
24210            _subscriptions: vec![],
24211        }
24212    }
24213
24214    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24215        self.block_ids.extend(block_ids)
24216    }
24217
24218    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24219        if let Some(editor) = self.editor.upgrade() {
24220            let message = self
24221                .prompt
24222                .read(cx)
24223                .buffer
24224                .read(cx)
24225                .as_singleton()
24226                .expect("A multi buffer in breakpoint prompt isn't possible")
24227                .read(cx)
24228                .as_rope()
24229                .to_string();
24230
24231            editor.update(cx, |editor, cx| {
24232                editor.edit_breakpoint_at_anchor(
24233                    self.breakpoint_anchor,
24234                    self.breakpoint.clone(),
24235                    match self.edit_action {
24236                        BreakpointPromptEditAction::Log => {
24237                            BreakpointEditAction::EditLogMessage(message.into())
24238                        }
24239                        BreakpointPromptEditAction::Condition => {
24240                            BreakpointEditAction::EditCondition(message.into())
24241                        }
24242                        BreakpointPromptEditAction::HitCondition => {
24243                            BreakpointEditAction::EditHitCondition(message.into())
24244                        }
24245                    },
24246                    cx,
24247                );
24248
24249                editor.remove_blocks(self.block_ids.clone(), None, cx);
24250                cx.focus_self(window);
24251            });
24252        }
24253    }
24254
24255    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24256        self.editor
24257            .update(cx, |editor, cx| {
24258                editor.remove_blocks(self.block_ids.clone(), None, cx);
24259                window.focus(&editor.focus_handle);
24260            })
24261            .log_err();
24262    }
24263
24264    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24265        let settings = ThemeSettings::get_global(cx);
24266        let text_style = TextStyle {
24267            color: if self.prompt.read(cx).read_only(cx) {
24268                cx.theme().colors().text_disabled
24269            } else {
24270                cx.theme().colors().text
24271            },
24272            font_family: settings.buffer_font.family.clone(),
24273            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24274            font_size: settings.buffer_font_size(cx).into(),
24275            font_weight: settings.buffer_font.weight,
24276            line_height: relative(settings.buffer_line_height.value()),
24277            ..Default::default()
24278        };
24279        EditorElement::new(
24280            &self.prompt,
24281            EditorStyle {
24282                background: cx.theme().colors().editor_background,
24283                local_player: cx.theme().players().local(),
24284                text: text_style,
24285                ..Default::default()
24286            },
24287        )
24288    }
24289}
24290
24291impl Render for BreakpointPromptEditor {
24292    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24293        let editor_margins = *self.editor_margins.lock();
24294        let gutter_dimensions = editor_margins.gutter;
24295        h_flex()
24296            .key_context("Editor")
24297            .bg(cx.theme().colors().editor_background)
24298            .border_y_1()
24299            .border_color(cx.theme().status().info_border)
24300            .size_full()
24301            .py(window.line_height() / 2.5)
24302            .on_action(cx.listener(Self::confirm))
24303            .on_action(cx.listener(Self::cancel))
24304            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24305            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24306    }
24307}
24308
24309impl Focusable for BreakpointPromptEditor {
24310    fn focus_handle(&self, cx: &App) -> FocusHandle {
24311        self.prompt.focus_handle(cx)
24312    }
24313}
24314
24315fn all_edits_insertions_or_deletions(
24316    edits: &Vec<(Range<Anchor>, String)>,
24317    snapshot: &MultiBufferSnapshot,
24318) -> bool {
24319    let mut all_insertions = true;
24320    let mut all_deletions = true;
24321
24322    for (range, new_text) in edits.iter() {
24323        let range_is_empty = range.to_offset(snapshot).is_empty();
24324        let text_is_empty = new_text.is_empty();
24325
24326        if range_is_empty != text_is_empty {
24327            if range_is_empty {
24328                all_deletions = false;
24329            } else {
24330                all_insertions = false;
24331            }
24332        } else {
24333            return false;
24334        }
24335
24336        if !all_insertions && !all_deletions {
24337            return false;
24338        }
24339    }
24340    all_insertions || all_deletions
24341}
24342
24343struct MissingEditPredictionKeybindingTooltip;
24344
24345impl Render for MissingEditPredictionKeybindingTooltip {
24346    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24347        ui::tooltip_container(window, cx, |container, _, cx| {
24348            container
24349                .flex_shrink_0()
24350                .max_w_80()
24351                .min_h(rems_from_px(124.))
24352                .justify_between()
24353                .child(
24354                    v_flex()
24355                        .flex_1()
24356                        .text_ui_sm(cx)
24357                        .child(Label::new("Conflict with Accept Keybinding"))
24358                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24359                )
24360                .child(
24361                    h_flex()
24362                        .pb_1()
24363                        .gap_1()
24364                        .items_end()
24365                        .w_full()
24366                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24367                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24368                        }))
24369                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24370                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24371                        })),
24372                )
24373        })
24374    }
24375}
24376
24377#[derive(Debug, Clone, Copy, PartialEq)]
24378pub struct LineHighlight {
24379    pub background: Background,
24380    pub border: Option<gpui::Hsla>,
24381    pub include_gutter: bool,
24382    pub type_id: Option<TypeId>,
24383}
24384
24385struct LineManipulationResult {
24386    pub new_text: String,
24387    pub line_count_before: usize,
24388    pub line_count_after: usize,
24389}
24390
24391fn render_diff_hunk_controls(
24392    row: u32,
24393    status: &DiffHunkStatus,
24394    hunk_range: Range<Anchor>,
24395    is_created_file: bool,
24396    line_height: Pixels,
24397    editor: &Entity<Editor>,
24398    _window: &mut Window,
24399    cx: &mut App,
24400) -> AnyElement {
24401    h_flex()
24402        .h(line_height)
24403        .mr_1()
24404        .gap_1()
24405        .px_0p5()
24406        .pb_1()
24407        .border_x_1()
24408        .border_b_1()
24409        .border_color(cx.theme().colors().border_variant)
24410        .rounded_b_lg()
24411        .bg(cx.theme().colors().editor_background)
24412        .gap_1()
24413        .block_mouse_except_scroll()
24414        .shadow_md()
24415        .child(if status.has_secondary_hunk() {
24416            Button::new(("stage", row as u64), "Stage")
24417                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24418                .tooltip({
24419                    let focus_handle = editor.focus_handle(cx);
24420                    move |window, cx| {
24421                        Tooltip::for_action_in(
24422                            "Stage Hunk",
24423                            &::git::ToggleStaged,
24424                            &focus_handle,
24425                            window,
24426                            cx,
24427                        )
24428                    }
24429                })
24430                .on_click({
24431                    let editor = editor.clone();
24432                    move |_event, _window, cx| {
24433                        editor.update(cx, |editor, cx| {
24434                            editor.stage_or_unstage_diff_hunks(
24435                                true,
24436                                vec![hunk_range.start..hunk_range.start],
24437                                cx,
24438                            );
24439                        });
24440                    }
24441                })
24442        } else {
24443            Button::new(("unstage", row as u64), "Unstage")
24444                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24445                .tooltip({
24446                    let focus_handle = editor.focus_handle(cx);
24447                    move |window, cx| {
24448                        Tooltip::for_action_in(
24449                            "Unstage Hunk",
24450                            &::git::ToggleStaged,
24451                            &focus_handle,
24452                            window,
24453                            cx,
24454                        )
24455                    }
24456                })
24457                .on_click({
24458                    let editor = editor.clone();
24459                    move |_event, _window, cx| {
24460                        editor.update(cx, |editor, cx| {
24461                            editor.stage_or_unstage_diff_hunks(
24462                                false,
24463                                vec![hunk_range.start..hunk_range.start],
24464                                cx,
24465                            );
24466                        });
24467                    }
24468                })
24469        })
24470        .child(
24471            Button::new(("restore", row as u64), "Restore")
24472                .tooltip({
24473                    let focus_handle = editor.focus_handle(cx);
24474                    move |window, cx| {
24475                        Tooltip::for_action_in(
24476                            "Restore Hunk",
24477                            &::git::Restore,
24478                            &focus_handle,
24479                            window,
24480                            cx,
24481                        )
24482                    }
24483                })
24484                .on_click({
24485                    let editor = editor.clone();
24486                    move |_event, window, cx| {
24487                        editor.update(cx, |editor, cx| {
24488                            let snapshot = editor.snapshot(window, cx);
24489                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24490                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24491                        });
24492                    }
24493                })
24494                .disabled(is_created_file),
24495        )
24496        .when(
24497            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24498            |el| {
24499                el.child(
24500                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24501                        .shape(IconButtonShape::Square)
24502                        .icon_size(IconSize::Small)
24503                        // .disabled(!has_multiple_hunks)
24504                        .tooltip({
24505                            let focus_handle = editor.focus_handle(cx);
24506                            move |window, cx| {
24507                                Tooltip::for_action_in(
24508                                    "Next Hunk",
24509                                    &GoToHunk,
24510                                    &focus_handle,
24511                                    window,
24512                                    cx,
24513                                )
24514                            }
24515                        })
24516                        .on_click({
24517                            let editor = editor.clone();
24518                            move |_event, window, cx| {
24519                                editor.update(cx, |editor, cx| {
24520                                    let snapshot = editor.snapshot(window, cx);
24521                                    let position =
24522                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24523                                    editor.go_to_hunk_before_or_after_position(
24524                                        &snapshot,
24525                                        position,
24526                                        Direction::Next,
24527                                        window,
24528                                        cx,
24529                                    );
24530                                    editor.expand_selected_diff_hunks(cx);
24531                                });
24532                            }
24533                        }),
24534                )
24535                .child(
24536                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24537                        .shape(IconButtonShape::Square)
24538                        .icon_size(IconSize::Small)
24539                        // .disabled(!has_multiple_hunks)
24540                        .tooltip({
24541                            let focus_handle = editor.focus_handle(cx);
24542                            move |window, cx| {
24543                                Tooltip::for_action_in(
24544                                    "Previous Hunk",
24545                                    &GoToPreviousHunk,
24546                                    &focus_handle,
24547                                    window,
24548                                    cx,
24549                                )
24550                            }
24551                        })
24552                        .on_click({
24553                            let editor = editor.clone();
24554                            move |_event, window, cx| {
24555                                editor.update(cx, |editor, cx| {
24556                                    let snapshot = editor.snapshot(window, cx);
24557                                    let point =
24558                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24559                                    editor.go_to_hunk_before_or_after_position(
24560                                        &snapshot,
24561                                        point,
24562                                        Direction::Prev,
24563                                        window,
24564                                        cx,
24565                                    );
24566                                    editor.expand_selected_diff_hunks(cx);
24567                                });
24568                            }
24569                        }),
24570                )
24571            },
24572        )
24573        .into_any_element()
24574}
24575
24576pub fn multibuffer_context_lines(cx: &App) -> u32 {
24577    EditorSettings::try_get(cx)
24578        .map(|settings| settings.excerpt_context_lines)
24579        .unwrap_or(2)
24580        .min(32)
24581}