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};
   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, CodeLabel, CursorShape, DiagnosticEntry,
  125    DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize,
  126    Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject,
  127    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::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    HighlightStyle {
  596        color: Some(cx.theme().status().hint),
  597        background_color: show_background.then(|| cx.theme().status().hint_background),
  598        ..HighlightStyle::default()
  599    }
  600}
  601
  602pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  603    EditPredictionStyles {
  604        insertion: HighlightStyle {
  605            color: Some(cx.theme().status().predictive),
  606            ..HighlightStyle::default()
  607        },
  608        whitespace: HighlightStyle {
  609            background_color: Some(cx.theme().status().created_background),
  610            ..HighlightStyle::default()
  611        },
  612    }
  613}
  614
  615type CompletionId = usize;
  616
  617pub(crate) enum EditDisplayMode {
  618    TabAccept,
  619    DiffPopover,
  620    Inline,
  621}
  622
  623enum EditPrediction {
  624    Edit {
  625        edits: Vec<(Range<Anchor>, String)>,
  626        edit_preview: Option<EditPreview>,
  627        display_mode: EditDisplayMode,
  628        snapshot: BufferSnapshot,
  629    },
  630    Move {
  631        target: Anchor,
  632        snapshot: BufferSnapshot,
  633    },
  634}
  635
  636struct EditPredictionState {
  637    inlay_ids: Vec<InlayId>,
  638    completion: EditPrediction,
  639    completion_id: Option<SharedString>,
  640    invalidation_range: Range<Anchor>,
  641}
  642
  643enum EditPredictionSettings {
  644    Disabled,
  645    Enabled {
  646        show_in_menu: bool,
  647        preview_requires_modifier: bool,
  648    },
  649}
  650
  651enum EditPredictionHighlight {}
  652
  653#[derive(Debug, Clone)]
  654struct InlineDiagnostic {
  655    message: SharedString,
  656    group_id: usize,
  657    is_primary: bool,
  658    start: Point,
  659    severity: lsp::DiagnosticSeverity,
  660}
  661
  662pub enum MenuEditPredictionsPolicy {
  663    Never,
  664    ByProvider,
  665}
  666
  667pub enum EditPredictionPreview {
  668    /// Modifier is not pressed
  669    Inactive { released_too_fast: bool },
  670    /// Modifier pressed
  671    Active {
  672        since: Instant,
  673        previous_scroll_position: Option<ScrollAnchor>,
  674    },
  675}
  676
  677impl EditPredictionPreview {
  678    pub fn released_too_fast(&self) -> bool {
  679        match self {
  680            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  681            EditPredictionPreview::Active { .. } => false,
  682        }
  683    }
  684
  685    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  686        if let EditPredictionPreview::Active {
  687            previous_scroll_position,
  688            ..
  689        } = self
  690        {
  691            *previous_scroll_position = scroll_position;
  692        }
  693    }
  694}
  695
  696pub struct ContextMenuOptions {
  697    pub min_entries_visible: usize,
  698    pub max_entries_visible: usize,
  699    pub placement: Option<ContextMenuPlacement>,
  700}
  701
  702#[derive(Debug, Clone, PartialEq, Eq)]
  703pub enum ContextMenuPlacement {
  704    Above,
  705    Below,
  706}
  707
  708#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  709struct EditorActionId(usize);
  710
  711impl EditorActionId {
  712    pub fn post_inc(&mut self) -> Self {
  713        let answer = self.0;
  714
  715        *self = Self(answer + 1);
  716
  717        Self(answer)
  718    }
  719}
  720
  721// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  722// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  723
  724type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  725type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  726
  727#[derive(Default)]
  728struct ScrollbarMarkerState {
  729    scrollbar_size: Size<Pixels>,
  730    dirty: bool,
  731    markers: Arc<[PaintQuad]>,
  732    pending_refresh: Option<Task<Result<()>>>,
  733}
  734
  735impl ScrollbarMarkerState {
  736    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  737        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  738    }
  739}
  740
  741#[derive(Clone, Copy, PartialEq, Eq)]
  742pub enum MinimapVisibility {
  743    Disabled,
  744    Enabled {
  745        /// The configuration currently present in the users settings.
  746        setting_configuration: bool,
  747        /// Whether to override the currently set visibility from the users setting.
  748        toggle_override: bool,
  749    },
  750}
  751
  752impl MinimapVisibility {
  753    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  754        if mode.is_full() {
  755            Self::Enabled {
  756                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  757                toggle_override: false,
  758            }
  759        } else {
  760            Self::Disabled
  761        }
  762    }
  763
  764    fn hidden(&self) -> Self {
  765        match *self {
  766            Self::Enabled {
  767                setting_configuration,
  768                ..
  769            } => Self::Enabled {
  770                setting_configuration,
  771                toggle_override: setting_configuration,
  772            },
  773            Self::Disabled => Self::Disabled,
  774        }
  775    }
  776
  777    fn disabled(&self) -> bool {
  778        matches!(*self, Self::Disabled)
  779    }
  780
  781    fn settings_visibility(&self) -> bool {
  782        match *self {
  783            Self::Enabled {
  784                setting_configuration,
  785                ..
  786            } => setting_configuration,
  787            _ => false,
  788        }
  789    }
  790
  791    fn visible(&self) -> bool {
  792        match *self {
  793            Self::Enabled {
  794                setting_configuration,
  795                toggle_override,
  796            } => setting_configuration ^ toggle_override,
  797            _ => false,
  798        }
  799    }
  800
  801    fn toggle_visibility(&self) -> Self {
  802        match *self {
  803            Self::Enabled {
  804                toggle_override,
  805                setting_configuration,
  806            } => Self::Enabled {
  807                setting_configuration,
  808                toggle_override: !toggle_override,
  809            },
  810            Self::Disabled => Self::Disabled,
  811        }
  812    }
  813}
  814
  815#[derive(Clone, Debug)]
  816struct RunnableTasks {
  817    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  818    offset: multi_buffer::Anchor,
  819    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  820    column: u32,
  821    // Values of all named captures, including those starting with '_'
  822    extra_variables: HashMap<String, String>,
  823    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  824    context_range: Range<BufferOffset>,
  825}
  826
  827impl RunnableTasks {
  828    fn resolve<'a>(
  829        &'a self,
  830        cx: &'a task::TaskContext,
  831    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  832        self.templates.iter().filter_map(|(kind, template)| {
  833            template
  834                .resolve_task(&kind.to_id_base(), cx)
  835                .map(|task| (kind.clone(), task))
  836        })
  837    }
  838}
  839
  840#[derive(Clone)]
  841pub struct ResolvedTasks {
  842    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  843    position: Anchor,
  844}
  845
  846#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  847struct BufferOffset(usize);
  848
  849/// Addons allow storing per-editor state in other crates (e.g. Vim)
  850pub trait Addon: 'static {
  851    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  852
  853    fn render_buffer_header_controls(
  854        &self,
  855        _: &ExcerptInfo,
  856        _: &Window,
  857        _: &App,
  858    ) -> Option<AnyElement> {
  859        None
  860    }
  861
  862    fn to_any(&self) -> &dyn std::any::Any;
  863
  864    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  865        None
  866    }
  867}
  868
  869struct ChangeLocation {
  870    current: Option<Vec<Anchor>>,
  871    original: Vec<Anchor>,
  872}
  873impl ChangeLocation {
  874    fn locations(&self) -> &[Anchor] {
  875        self.current.as_ref().unwrap_or(&self.original)
  876    }
  877}
  878
  879/// A set of caret positions, registered when the editor was edited.
  880pub struct ChangeList {
  881    changes: Vec<ChangeLocation>,
  882    /// Currently "selected" change.
  883    position: Option<usize>,
  884}
  885
  886impl ChangeList {
  887    pub fn new() -> Self {
  888        Self {
  889            changes: Vec::new(),
  890            position: None,
  891        }
  892    }
  893
  894    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  895    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  896    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  897        if self.changes.is_empty() {
  898            return None;
  899        }
  900
  901        let prev = self.position.unwrap_or(self.changes.len());
  902        let next = if direction == Direction::Prev {
  903            prev.saturating_sub(count)
  904        } else {
  905            (prev + count).min(self.changes.len() - 1)
  906        };
  907        self.position = Some(next);
  908        self.changes.get(next).map(|change| change.locations())
  909    }
  910
  911    /// Adds a new change to the list, resetting the change list position.
  912    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  913        self.position.take();
  914        if let Some(last) = self.changes.last_mut()
  915            && group
  916        {
  917            last.current = Some(new_positions)
  918        } else {
  919            self.changes.push(ChangeLocation {
  920                original: new_positions,
  921                current: None,
  922            });
  923        }
  924    }
  925
  926    pub fn last(&self) -> Option<&[Anchor]> {
  927        self.changes.last().map(|change| change.locations())
  928    }
  929
  930    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  931        self.changes.last().map(|change| change.original.as_slice())
  932    }
  933
  934    pub fn invert_last_group(&mut self) {
  935        if let Some(last) = self.changes.last_mut()
  936            && let Some(current) = last.current.as_mut()
  937        {
  938            mem::swap(&mut last.original, current);
  939        }
  940    }
  941}
  942
  943#[derive(Clone)]
  944struct InlineBlamePopoverState {
  945    scroll_handle: ScrollHandle,
  946    commit_message: Option<ParsedCommitMessage>,
  947    markdown: Entity<Markdown>,
  948}
  949
  950struct InlineBlamePopover {
  951    position: gpui::Point<Pixels>,
  952    hide_task: Option<Task<()>>,
  953    popover_bounds: Option<Bounds<Pixels>>,
  954    popover_state: InlineBlamePopoverState,
  955    keyboard_grace: bool,
  956}
  957
  958enum SelectionDragState {
  959    /// State when no drag related activity is detected.
  960    None,
  961    /// State when the mouse is down on a selection that is about to be dragged.
  962    ReadyToDrag {
  963        selection: Selection<Anchor>,
  964        click_position: gpui::Point<Pixels>,
  965        mouse_down_time: Instant,
  966    },
  967    /// State when the mouse is dragging the selection in the editor.
  968    Dragging {
  969        selection: Selection<Anchor>,
  970        drop_cursor: Selection<Anchor>,
  971        hide_drop_cursor: bool,
  972    },
  973}
  974
  975enum ColumnarSelectionState {
  976    FromMouse {
  977        selection_tail: Anchor,
  978        display_point: Option<DisplayPoint>,
  979    },
  980    FromSelection {
  981        selection_tail: Anchor,
  982    },
  983}
  984
  985/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  986/// a breakpoint on them.
  987#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  988struct PhantomBreakpointIndicator {
  989    display_row: DisplayRow,
  990    /// There's a small debounce between hovering over the line and showing the indicator.
  991    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  992    is_active: bool,
  993    collides_with_existing_breakpoint: bool,
  994}
  995
  996/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  997///
  998/// See the [module level documentation](self) for more information.
  999pub struct Editor {
 1000    focus_handle: FocusHandle,
 1001    last_focused_descendant: Option<WeakFocusHandle>,
 1002    /// The text buffer being edited
 1003    buffer: Entity<MultiBuffer>,
 1004    /// Map of how text in the buffer should be displayed.
 1005    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1006    pub display_map: Entity<DisplayMap>,
 1007    placeholder_display_map: Option<Entity<DisplayMap>>,
 1008    pub selections: SelectionsCollection,
 1009    pub scroll_manager: ScrollManager,
 1010    /// When inline assist editors are linked, they all render cursors because
 1011    /// typing enters text into each of them, even the ones that aren't focused.
 1012    pub(crate) show_cursor_when_unfocused: bool,
 1013    columnar_selection_state: Option<ColumnarSelectionState>,
 1014    add_selections_state: Option<AddSelectionsState>,
 1015    select_next_state: Option<SelectNextState>,
 1016    select_prev_state: Option<SelectNextState>,
 1017    selection_history: SelectionHistory,
 1018    defer_selection_effects: bool,
 1019    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1020    autoclose_regions: Vec<AutocloseRegion>,
 1021    snippet_stack: InvalidationStack<SnippetState>,
 1022    select_syntax_node_history: SelectSyntaxNodeHistory,
 1023    ime_transaction: Option<TransactionId>,
 1024    pub diagnostics_max_severity: DiagnosticSeverity,
 1025    active_diagnostics: ActiveDiagnostic,
 1026    show_inline_diagnostics: bool,
 1027    inline_diagnostics_update: Task<()>,
 1028    inline_diagnostics_enabled: bool,
 1029    diagnostics_enabled: bool,
 1030    word_completions_enabled: bool,
 1031    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1032    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1033    hard_wrap: Option<usize>,
 1034    project: Option<Entity<Project>>,
 1035    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1036    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1037    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1038    blink_manager: Entity<BlinkManager>,
 1039    show_cursor_names: bool,
 1040    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1041    pub show_local_selections: bool,
 1042    mode: EditorMode,
 1043    show_breadcrumbs: bool,
 1044    show_gutter: bool,
 1045    show_scrollbars: ScrollbarAxes,
 1046    minimap_visibility: MinimapVisibility,
 1047    offset_content: bool,
 1048    disable_expand_excerpt_buttons: bool,
 1049    show_line_numbers: Option<bool>,
 1050    use_relative_line_numbers: Option<bool>,
 1051    show_git_diff_gutter: Option<bool>,
 1052    show_code_actions: Option<bool>,
 1053    show_runnables: Option<bool>,
 1054    show_breakpoints: Option<bool>,
 1055    show_wrap_guides: Option<bool>,
 1056    show_indent_guides: Option<bool>,
 1057    highlight_order: usize,
 1058    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1059    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1060    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1061    scrollbar_marker_state: ScrollbarMarkerState,
 1062    active_indent_guides_state: ActiveIndentGuidesState,
 1063    nav_history: Option<ItemNavHistory>,
 1064    context_menu: RefCell<Option<CodeContextMenu>>,
 1065    context_menu_options: Option<ContextMenuOptions>,
 1066    mouse_context_menu: Option<MouseContextMenu>,
 1067    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1068    inline_blame_popover: Option<InlineBlamePopover>,
 1069    inline_blame_popover_show_task: Option<Task<()>>,
 1070    signature_help_state: SignatureHelpState,
 1071    auto_signature_help: Option<bool>,
 1072    find_all_references_task_sources: Vec<Anchor>,
 1073    next_completion_id: CompletionId,
 1074    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1075    code_actions_task: Option<Task<Result<()>>>,
 1076    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1077    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1078    document_highlights_task: Option<Task<()>>,
 1079    linked_editing_range_task: Option<Task<Option<()>>>,
 1080    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1081    pending_rename: Option<RenameState>,
 1082    searchable: bool,
 1083    cursor_shape: CursorShape,
 1084    current_line_highlight: Option<CurrentLineHighlight>,
 1085    collapse_matches: bool,
 1086    autoindent_mode: Option<AutoindentMode>,
 1087    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1088    input_enabled: bool,
 1089    use_modal_editing: bool,
 1090    read_only: bool,
 1091    leader_id: Option<CollaboratorId>,
 1092    remote_id: Option<ViewId>,
 1093    pub hover_state: HoverState,
 1094    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1095    gutter_hovered: bool,
 1096    hovered_link_state: Option<HoveredLinkState>,
 1097    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1098    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1099    active_edit_prediction: Option<EditPredictionState>,
 1100    /// Used to prevent flickering as the user types while the menu is open
 1101    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1102    edit_prediction_settings: EditPredictionSettings,
 1103    edit_predictions_hidden_for_vim_mode: bool,
 1104    show_edit_predictions_override: Option<bool>,
 1105    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1106    edit_prediction_preview: EditPredictionPreview,
 1107    edit_prediction_indent_conflict: bool,
 1108    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1109    inlay_hint_cache: InlayHintCache,
 1110    next_inlay_id: usize,
 1111    _subscriptions: Vec<Subscription>,
 1112    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1113    gutter_dimensions: GutterDimensions,
 1114    style: Option<EditorStyle>,
 1115    text_style_refinement: Option<TextStyleRefinement>,
 1116    next_editor_action_id: EditorActionId,
 1117    editor_actions: Rc<
 1118        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1119    >,
 1120    use_autoclose: bool,
 1121    use_auto_surround: bool,
 1122    auto_replace_emoji_shortcode: bool,
 1123    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1124    show_git_blame_gutter: bool,
 1125    show_git_blame_inline: bool,
 1126    show_git_blame_inline_delay_task: Option<Task<()>>,
 1127    git_blame_inline_enabled: bool,
 1128    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1129    serialize_dirty_buffers: bool,
 1130    show_selection_menu: Option<bool>,
 1131    blame: Option<Entity<GitBlame>>,
 1132    blame_subscription: Option<Subscription>,
 1133    custom_context_menu: Option<
 1134        Box<
 1135            dyn 'static
 1136                + Fn(
 1137                    &mut Self,
 1138                    DisplayPoint,
 1139                    &mut Window,
 1140                    &mut Context<Self>,
 1141                ) -> Option<Entity<ui::ContextMenu>>,
 1142        >,
 1143    >,
 1144    last_bounds: Option<Bounds<Pixels>>,
 1145    last_position_map: Option<Rc<PositionMap>>,
 1146    expect_bounds_change: Option<Bounds<Pixels>>,
 1147    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1148    tasks_update_task: Option<Task<()>>,
 1149    breakpoint_store: Option<Entity<BreakpointStore>>,
 1150    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1151    hovered_diff_hunk_row: Option<DisplayRow>,
 1152    pull_diagnostics_task: Task<()>,
 1153    in_project_search: bool,
 1154    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1155    breadcrumb_header: Option<String>,
 1156    focused_block: Option<FocusedBlock>,
 1157    next_scroll_position: NextScrollCursorCenterTopBottom,
 1158    addons: HashMap<TypeId, Box<dyn Addon>>,
 1159    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1160    load_diff_task: Option<Shared<Task<()>>>,
 1161    /// Whether we are temporarily displaying a diff other than git's
 1162    temporary_diff_override: bool,
 1163    selection_mark_mode: bool,
 1164    toggle_fold_multiple_buffers: Task<()>,
 1165    _scroll_cursor_center_top_bottom_task: Task<()>,
 1166    serialize_selections: Task<()>,
 1167    serialize_folds: Task<()>,
 1168    mouse_cursor_hidden: bool,
 1169    minimap: Option<Entity<Self>>,
 1170    hide_mouse_mode: HideMouseMode,
 1171    pub change_list: ChangeList,
 1172    inline_value_cache: InlineValueCache,
 1173    selection_drag_state: SelectionDragState,
 1174    next_color_inlay_id: usize,
 1175    colors: Option<LspColorData>,
 1176    folding_newlines: Task<()>,
 1177    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1178}
 1179
 1180#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1181enum NextScrollCursorCenterTopBottom {
 1182    #[default]
 1183    Center,
 1184    Top,
 1185    Bottom,
 1186}
 1187
 1188impl NextScrollCursorCenterTopBottom {
 1189    fn next(&self) -> Self {
 1190        match self {
 1191            Self::Center => Self::Top,
 1192            Self::Top => Self::Bottom,
 1193            Self::Bottom => Self::Center,
 1194        }
 1195    }
 1196}
 1197
 1198#[derive(Clone)]
 1199pub struct EditorSnapshot {
 1200    pub mode: EditorMode,
 1201    show_gutter: bool,
 1202    show_line_numbers: Option<bool>,
 1203    show_git_diff_gutter: Option<bool>,
 1204    show_code_actions: Option<bool>,
 1205    show_runnables: Option<bool>,
 1206    show_breakpoints: Option<bool>,
 1207    git_blame_gutter_max_author_length: Option<usize>,
 1208    pub display_snapshot: DisplaySnapshot,
 1209    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1210    is_focused: bool,
 1211    scroll_anchor: ScrollAnchor,
 1212    ongoing_scroll: OngoingScroll,
 1213    current_line_highlight: CurrentLineHighlight,
 1214    gutter_hovered: bool,
 1215}
 1216
 1217#[derive(Default, Debug, Clone, Copy)]
 1218pub struct GutterDimensions {
 1219    pub left_padding: Pixels,
 1220    pub right_padding: Pixels,
 1221    pub width: Pixels,
 1222    pub margin: Pixels,
 1223    pub git_blame_entries_width: Option<Pixels>,
 1224}
 1225
 1226impl GutterDimensions {
 1227    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1228        Self {
 1229            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1230            ..Default::default()
 1231        }
 1232    }
 1233
 1234    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1235        -cx.text_system().descent(font_id, font_size)
 1236    }
 1237    /// The full width of the space taken up by the gutter.
 1238    pub fn full_width(&self) -> Pixels {
 1239        self.margin + self.width
 1240    }
 1241
 1242    /// The width of the space reserved for the fold indicators,
 1243    /// use alongside 'justify_end' and `gutter_width` to
 1244    /// right align content with the line numbers
 1245    pub fn fold_area_width(&self) -> Pixels {
 1246        self.margin + self.right_padding
 1247    }
 1248}
 1249
 1250struct CharacterDimensions {
 1251    em_width: Pixels,
 1252    em_advance: Pixels,
 1253    line_height: Pixels,
 1254}
 1255
 1256#[derive(Debug)]
 1257pub struct RemoteSelection {
 1258    pub replica_id: ReplicaId,
 1259    pub selection: Selection<Anchor>,
 1260    pub cursor_shape: CursorShape,
 1261    pub collaborator_id: CollaboratorId,
 1262    pub line_mode: bool,
 1263    pub user_name: Option<SharedString>,
 1264    pub color: PlayerColor,
 1265}
 1266
 1267#[derive(Clone, Debug)]
 1268struct SelectionHistoryEntry {
 1269    selections: Arc<[Selection<Anchor>]>,
 1270    select_next_state: Option<SelectNextState>,
 1271    select_prev_state: Option<SelectNextState>,
 1272    add_selections_state: Option<AddSelectionsState>,
 1273}
 1274
 1275#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1276enum SelectionHistoryMode {
 1277    Normal,
 1278    Undoing,
 1279    Redoing,
 1280    Skipping,
 1281}
 1282
 1283#[derive(Clone, PartialEq, Eq, Hash)]
 1284struct HoveredCursor {
 1285    replica_id: u16,
 1286    selection_id: usize,
 1287}
 1288
 1289impl Default for SelectionHistoryMode {
 1290    fn default() -> Self {
 1291        Self::Normal
 1292    }
 1293}
 1294
 1295#[derive(Debug)]
 1296/// SelectionEffects controls the side-effects of updating the selection.
 1297///
 1298/// The default behaviour does "what you mostly want":
 1299/// - it pushes to the nav history if the cursor moved by >10 lines
 1300/// - it re-triggers completion requests
 1301/// - it scrolls to fit
 1302///
 1303/// You might want to modify these behaviours. For example when doing a "jump"
 1304/// like go to definition, we always want to add to nav history; but when scrolling
 1305/// in vim mode we never do.
 1306///
 1307/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1308/// move.
 1309#[derive(Clone)]
 1310pub struct SelectionEffects {
 1311    nav_history: Option<bool>,
 1312    completions: bool,
 1313    scroll: Option<Autoscroll>,
 1314}
 1315
 1316impl Default for SelectionEffects {
 1317    fn default() -> Self {
 1318        Self {
 1319            nav_history: None,
 1320            completions: true,
 1321            scroll: Some(Autoscroll::fit()),
 1322        }
 1323    }
 1324}
 1325impl SelectionEffects {
 1326    pub fn scroll(scroll: Autoscroll) -> Self {
 1327        Self {
 1328            scroll: Some(scroll),
 1329            ..Default::default()
 1330        }
 1331    }
 1332
 1333    pub fn no_scroll() -> Self {
 1334        Self {
 1335            scroll: None,
 1336            ..Default::default()
 1337        }
 1338    }
 1339
 1340    pub fn completions(self, completions: bool) -> Self {
 1341        Self {
 1342            completions,
 1343            ..self
 1344        }
 1345    }
 1346
 1347    pub fn nav_history(self, nav_history: bool) -> Self {
 1348        Self {
 1349            nav_history: Some(nav_history),
 1350            ..self
 1351        }
 1352    }
 1353}
 1354
 1355struct DeferredSelectionEffectsState {
 1356    changed: bool,
 1357    effects: SelectionEffects,
 1358    old_cursor_position: Anchor,
 1359    history_entry: SelectionHistoryEntry,
 1360}
 1361
 1362#[derive(Default)]
 1363struct SelectionHistory {
 1364    #[allow(clippy::type_complexity)]
 1365    selections_by_transaction:
 1366        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1367    mode: SelectionHistoryMode,
 1368    undo_stack: VecDeque<SelectionHistoryEntry>,
 1369    redo_stack: VecDeque<SelectionHistoryEntry>,
 1370}
 1371
 1372impl SelectionHistory {
 1373    #[track_caller]
 1374    fn insert_transaction(
 1375        &mut self,
 1376        transaction_id: TransactionId,
 1377        selections: Arc<[Selection<Anchor>]>,
 1378    ) {
 1379        if selections.is_empty() {
 1380            log::error!(
 1381                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1382                std::panic::Location::caller()
 1383            );
 1384            return;
 1385        }
 1386        self.selections_by_transaction
 1387            .insert(transaction_id, (selections, None));
 1388    }
 1389
 1390    #[allow(clippy::type_complexity)]
 1391    fn transaction(
 1392        &self,
 1393        transaction_id: TransactionId,
 1394    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1395        self.selections_by_transaction.get(&transaction_id)
 1396    }
 1397
 1398    #[allow(clippy::type_complexity)]
 1399    fn transaction_mut(
 1400        &mut self,
 1401        transaction_id: TransactionId,
 1402    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1403        self.selections_by_transaction.get_mut(&transaction_id)
 1404    }
 1405
 1406    fn push(&mut self, entry: SelectionHistoryEntry) {
 1407        if !entry.selections.is_empty() {
 1408            match self.mode {
 1409                SelectionHistoryMode::Normal => {
 1410                    self.push_undo(entry);
 1411                    self.redo_stack.clear();
 1412                }
 1413                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1414                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1415                SelectionHistoryMode::Skipping => {}
 1416            }
 1417        }
 1418    }
 1419
 1420    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1421        if self
 1422            .undo_stack
 1423            .back()
 1424            .is_none_or(|e| e.selections != entry.selections)
 1425        {
 1426            self.undo_stack.push_back(entry);
 1427            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1428                self.undo_stack.pop_front();
 1429            }
 1430        }
 1431    }
 1432
 1433    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1434        if self
 1435            .redo_stack
 1436            .back()
 1437            .is_none_or(|e| e.selections != entry.selections)
 1438        {
 1439            self.redo_stack.push_back(entry);
 1440            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1441                self.redo_stack.pop_front();
 1442            }
 1443        }
 1444    }
 1445}
 1446
 1447#[derive(Clone, Copy)]
 1448pub struct RowHighlightOptions {
 1449    pub autoscroll: bool,
 1450    pub include_gutter: bool,
 1451}
 1452
 1453impl Default for RowHighlightOptions {
 1454    fn default() -> Self {
 1455        Self {
 1456            autoscroll: Default::default(),
 1457            include_gutter: true,
 1458        }
 1459    }
 1460}
 1461
 1462struct RowHighlight {
 1463    index: usize,
 1464    range: Range<Anchor>,
 1465    color: Hsla,
 1466    options: RowHighlightOptions,
 1467    type_id: TypeId,
 1468}
 1469
 1470#[derive(Clone, Debug)]
 1471struct AddSelectionsState {
 1472    groups: Vec<AddSelectionsGroup>,
 1473}
 1474
 1475#[derive(Clone, Debug)]
 1476struct AddSelectionsGroup {
 1477    above: bool,
 1478    stack: Vec<usize>,
 1479}
 1480
 1481#[derive(Clone)]
 1482struct SelectNextState {
 1483    query: AhoCorasick,
 1484    wordwise: bool,
 1485    done: bool,
 1486}
 1487
 1488impl std::fmt::Debug for SelectNextState {
 1489    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1490        f.debug_struct(std::any::type_name::<Self>())
 1491            .field("wordwise", &self.wordwise)
 1492            .field("done", &self.done)
 1493            .finish()
 1494    }
 1495}
 1496
 1497#[derive(Debug)]
 1498struct AutocloseRegion {
 1499    selection_id: usize,
 1500    range: Range<Anchor>,
 1501    pair: BracketPair,
 1502}
 1503
 1504#[derive(Debug)]
 1505struct SnippetState {
 1506    ranges: Vec<Vec<Range<Anchor>>>,
 1507    active_index: usize,
 1508    choices: Vec<Option<Vec<String>>>,
 1509}
 1510
 1511#[doc(hidden)]
 1512pub struct RenameState {
 1513    pub range: Range<Anchor>,
 1514    pub old_name: Arc<str>,
 1515    pub editor: Entity<Editor>,
 1516    block_id: CustomBlockId,
 1517}
 1518
 1519struct InvalidationStack<T>(Vec<T>);
 1520
 1521struct RegisteredEditPredictionProvider {
 1522    provider: Arc<dyn EditPredictionProviderHandle>,
 1523    _subscription: Subscription,
 1524}
 1525
 1526#[derive(Debug, PartialEq, Eq)]
 1527pub struct ActiveDiagnosticGroup {
 1528    pub active_range: Range<Anchor>,
 1529    pub active_message: String,
 1530    pub group_id: usize,
 1531    pub blocks: HashSet<CustomBlockId>,
 1532}
 1533
 1534#[derive(Debug, PartialEq, Eq)]
 1535
 1536pub(crate) enum ActiveDiagnostic {
 1537    None,
 1538    All,
 1539    Group(ActiveDiagnosticGroup),
 1540}
 1541
 1542#[derive(Serialize, Deserialize, Clone, Debug)]
 1543pub struct ClipboardSelection {
 1544    /// The number of bytes in this selection.
 1545    pub len: usize,
 1546    /// Whether this was a full-line selection.
 1547    pub is_entire_line: bool,
 1548    /// The indentation of the first line when this content was originally copied.
 1549    pub first_line_indent: u32,
 1550}
 1551
 1552// selections, scroll behavior, was newest selection reversed
 1553type SelectSyntaxNodeHistoryState = (
 1554    Box<[Selection<usize>]>,
 1555    SelectSyntaxNodeScrollBehavior,
 1556    bool,
 1557);
 1558
 1559#[derive(Default)]
 1560struct SelectSyntaxNodeHistory {
 1561    stack: Vec<SelectSyntaxNodeHistoryState>,
 1562    // disable temporarily to allow changing selections without losing the stack
 1563    pub disable_clearing: bool,
 1564}
 1565
 1566impl SelectSyntaxNodeHistory {
 1567    pub fn try_clear(&mut self) {
 1568        if !self.disable_clearing {
 1569            self.stack.clear();
 1570        }
 1571    }
 1572
 1573    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1574        self.stack.push(selection);
 1575    }
 1576
 1577    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1578        self.stack.pop()
 1579    }
 1580}
 1581
 1582enum SelectSyntaxNodeScrollBehavior {
 1583    CursorTop,
 1584    FitSelection,
 1585    CursorBottom,
 1586}
 1587
 1588#[derive(Debug)]
 1589pub(crate) struct NavigationData {
 1590    cursor_anchor: Anchor,
 1591    cursor_position: Point,
 1592    scroll_anchor: ScrollAnchor,
 1593    scroll_top_row: u32,
 1594}
 1595
 1596#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1597pub enum GotoDefinitionKind {
 1598    Symbol,
 1599    Declaration,
 1600    Type,
 1601    Implementation,
 1602}
 1603
 1604#[derive(Debug, Clone)]
 1605enum InlayHintRefreshReason {
 1606    ModifiersChanged(bool),
 1607    Toggle(bool),
 1608    SettingsChange(InlayHintSettings),
 1609    NewLinesShown,
 1610    BufferEdited(HashSet<Arc<Language>>),
 1611    RefreshRequested,
 1612    ExcerptsRemoved(Vec<ExcerptId>),
 1613}
 1614
 1615impl InlayHintRefreshReason {
 1616    fn description(&self) -> &'static str {
 1617        match self {
 1618            Self::ModifiersChanged(_) => "modifiers changed",
 1619            Self::Toggle(_) => "toggle",
 1620            Self::SettingsChange(_) => "settings change",
 1621            Self::NewLinesShown => "new lines shown",
 1622            Self::BufferEdited(_) => "buffer edited",
 1623            Self::RefreshRequested => "refresh requested",
 1624            Self::ExcerptsRemoved(_) => "excerpts removed",
 1625        }
 1626    }
 1627}
 1628
 1629pub enum FormatTarget {
 1630    Buffers(HashSet<Entity<Buffer>>),
 1631    Ranges(Vec<Range<MultiBufferPoint>>),
 1632}
 1633
 1634pub(crate) struct FocusedBlock {
 1635    id: BlockId,
 1636    focus_handle: WeakFocusHandle,
 1637}
 1638
 1639#[derive(Clone)]
 1640enum JumpData {
 1641    MultiBufferRow {
 1642        row: MultiBufferRow,
 1643        line_offset_from_top: u32,
 1644    },
 1645    MultiBufferPoint {
 1646        excerpt_id: ExcerptId,
 1647        position: Point,
 1648        anchor: text::Anchor,
 1649        line_offset_from_top: u32,
 1650    },
 1651}
 1652
 1653pub enum MultibufferSelectionMode {
 1654    First,
 1655    All,
 1656}
 1657
 1658#[derive(Clone, Copy, Debug, Default)]
 1659pub struct RewrapOptions {
 1660    pub override_language_settings: bool,
 1661    pub preserve_existing_whitespace: bool,
 1662}
 1663
 1664impl Editor {
 1665    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1666        let buffer = cx.new(|cx| Buffer::local("", cx));
 1667        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1668        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1669    }
 1670
 1671    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1672        let buffer = cx.new(|cx| Buffer::local("", cx));
 1673        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1674        Self::new(EditorMode::full(), buffer, None, window, cx)
 1675    }
 1676
 1677    pub fn auto_height(
 1678        min_lines: usize,
 1679        max_lines: usize,
 1680        window: &mut Window,
 1681        cx: &mut Context<Self>,
 1682    ) -> Self {
 1683        let buffer = cx.new(|cx| Buffer::local("", cx));
 1684        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1685        Self::new(
 1686            EditorMode::AutoHeight {
 1687                min_lines,
 1688                max_lines: Some(max_lines),
 1689            },
 1690            buffer,
 1691            None,
 1692            window,
 1693            cx,
 1694        )
 1695    }
 1696
 1697    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1698    /// The editor grows as tall as needed to fit its content.
 1699    pub fn auto_height_unbounded(
 1700        min_lines: usize,
 1701        window: &mut Window,
 1702        cx: &mut Context<Self>,
 1703    ) -> Self {
 1704        let buffer = cx.new(|cx| Buffer::local("", cx));
 1705        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1706        Self::new(
 1707            EditorMode::AutoHeight {
 1708                min_lines,
 1709                max_lines: None,
 1710            },
 1711            buffer,
 1712            None,
 1713            window,
 1714            cx,
 1715        )
 1716    }
 1717
 1718    pub fn for_buffer(
 1719        buffer: Entity<Buffer>,
 1720        project: Option<Entity<Project>>,
 1721        window: &mut Window,
 1722        cx: &mut Context<Self>,
 1723    ) -> Self {
 1724        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1725        Self::new(EditorMode::full(), buffer, project, window, cx)
 1726    }
 1727
 1728    pub fn for_multibuffer(
 1729        buffer: Entity<MultiBuffer>,
 1730        project: Option<Entity<Project>>,
 1731        window: &mut Window,
 1732        cx: &mut Context<Self>,
 1733    ) -> Self {
 1734        Self::new(EditorMode::full(), buffer, project, window, cx)
 1735    }
 1736
 1737    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1738        let mut clone = Self::new(
 1739            self.mode.clone(),
 1740            self.buffer.clone(),
 1741            self.project.clone(),
 1742            window,
 1743            cx,
 1744        );
 1745        self.display_map.update(cx, |display_map, cx| {
 1746            let snapshot = display_map.snapshot(cx);
 1747            clone.display_map.update(cx, |display_map, cx| {
 1748                display_map.set_state(&snapshot, cx);
 1749            });
 1750        });
 1751        clone.folds_did_change(cx);
 1752        clone.selections.clone_state(&self.selections);
 1753        clone.scroll_manager.clone_state(&self.scroll_manager);
 1754        clone.searchable = self.searchable;
 1755        clone.read_only = self.read_only;
 1756        clone
 1757    }
 1758
 1759    pub fn new(
 1760        mode: EditorMode,
 1761        buffer: Entity<MultiBuffer>,
 1762        project: Option<Entity<Project>>,
 1763        window: &mut Window,
 1764        cx: &mut Context<Self>,
 1765    ) -> Self {
 1766        Editor::new_internal(mode, buffer, project, None, window, cx)
 1767    }
 1768
 1769    fn new_internal(
 1770        mode: EditorMode,
 1771        buffer: Entity<MultiBuffer>,
 1772        project: Option<Entity<Project>>,
 1773        display_map: Option<Entity<DisplayMap>>,
 1774        window: &mut Window,
 1775        cx: &mut Context<Self>,
 1776    ) -> Self {
 1777        debug_assert!(
 1778            display_map.is_none() || mode.is_minimap(),
 1779            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1780        );
 1781
 1782        let full_mode = mode.is_full();
 1783        let is_minimap = mode.is_minimap();
 1784        let diagnostics_max_severity = if full_mode {
 1785            EditorSettings::get_global(cx)
 1786                .diagnostics_max_severity
 1787                .unwrap_or(DiagnosticSeverity::Hint)
 1788        } else {
 1789            DiagnosticSeverity::Off
 1790        };
 1791        let style = window.text_style();
 1792        let font_size = style.font_size.to_pixels(window.rem_size());
 1793        let editor = cx.entity().downgrade();
 1794        let fold_placeholder = FoldPlaceholder {
 1795            constrain_width: false,
 1796            render: Arc::new(move |fold_id, fold_range, cx| {
 1797                let editor = editor.clone();
 1798                div()
 1799                    .id(fold_id)
 1800                    .bg(cx.theme().colors().ghost_element_background)
 1801                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1802                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1803                    .rounded_xs()
 1804                    .size_full()
 1805                    .cursor_pointer()
 1806                    .child("")
 1807                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1808                    .on_click(move |_, _window, cx| {
 1809                        editor
 1810                            .update(cx, |editor, cx| {
 1811                                editor.unfold_ranges(
 1812                                    &[fold_range.start..fold_range.end],
 1813                                    true,
 1814                                    false,
 1815                                    cx,
 1816                                );
 1817                                cx.stop_propagation();
 1818                            })
 1819                            .ok();
 1820                    })
 1821                    .into_any()
 1822            }),
 1823            merge_adjacent: true,
 1824            ..FoldPlaceholder::default()
 1825        };
 1826        let display_map = display_map.unwrap_or_else(|| {
 1827            cx.new(|cx| {
 1828                DisplayMap::new(
 1829                    buffer.clone(),
 1830                    style.font(),
 1831                    font_size,
 1832                    None,
 1833                    FILE_HEADER_HEIGHT,
 1834                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1835                    fold_placeholder,
 1836                    diagnostics_max_severity,
 1837                    cx,
 1838                )
 1839            })
 1840        });
 1841
 1842        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1843
 1844        let blink_manager = cx.new(|cx| {
 1845            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1846            if is_minimap {
 1847                blink_manager.disable(cx);
 1848            }
 1849            blink_manager
 1850        });
 1851
 1852        let soft_wrap_mode_override =
 1853            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1854
 1855        let mut project_subscriptions = Vec::new();
 1856        if full_mode && let Some(project) = project.as_ref() {
 1857            project_subscriptions.push(cx.subscribe_in(
 1858                project,
 1859                window,
 1860                |editor, _, event, window, cx| match event {
 1861                    project::Event::RefreshCodeLens => {
 1862                        // we always query lens with actions, without storing them, always refreshing them
 1863                    }
 1864                    project::Event::RefreshInlayHints => {
 1865                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1866                    }
 1867                    project::Event::LanguageServerAdded(..)
 1868                    | project::Event::LanguageServerRemoved(..) => {
 1869                        if editor.tasks_update_task.is_none() {
 1870                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1871                        }
 1872                    }
 1873                    project::Event::SnippetEdit(id, snippet_edits) => {
 1874                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1875                            let focus_handle = editor.focus_handle(cx);
 1876                            if focus_handle.is_focused(window) {
 1877                                let snapshot = buffer.read(cx).snapshot();
 1878                                for (range, snippet) in snippet_edits {
 1879                                    let editor_range =
 1880                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1881                                    editor
 1882                                        .insert_snippet(
 1883                                            &[editor_range],
 1884                                            snippet.clone(),
 1885                                            window,
 1886                                            cx,
 1887                                        )
 1888                                        .ok();
 1889                                }
 1890                            }
 1891                        }
 1892                    }
 1893                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1894                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1895                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1896                        }
 1897                    }
 1898
 1899                    project::Event::EntryRenamed(transaction) => {
 1900                        let Some(workspace) = editor.workspace() else {
 1901                            return;
 1902                        };
 1903                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1904                        else {
 1905                            return;
 1906                        };
 1907                        if active_editor.entity_id() == cx.entity_id() {
 1908                            let edited_buffers_already_open = {
 1909                                let other_editors: Vec<Entity<Editor>> = workspace
 1910                                    .read(cx)
 1911                                    .panes()
 1912                                    .iter()
 1913                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1914                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1915                                    .collect();
 1916
 1917                                transaction.0.keys().all(|buffer| {
 1918                                    other_editors.iter().any(|editor| {
 1919                                        let multi_buffer = editor.read(cx).buffer();
 1920                                        multi_buffer.read(cx).is_singleton()
 1921                                            && multi_buffer.read(cx).as_singleton().map_or(
 1922                                                false,
 1923                                                |singleton| {
 1924                                                    singleton.entity_id() == buffer.entity_id()
 1925                                                },
 1926                                            )
 1927                                    })
 1928                                })
 1929                            };
 1930
 1931                            if !edited_buffers_already_open {
 1932                                let workspace = workspace.downgrade();
 1933                                let transaction = transaction.clone();
 1934                                cx.defer_in(window, move |_, window, cx| {
 1935                                    cx.spawn_in(window, async move |editor, cx| {
 1936                                        Self::open_project_transaction(
 1937                                            &editor,
 1938                                            workspace,
 1939                                            transaction,
 1940                                            "Rename".to_string(),
 1941                                            cx,
 1942                                        )
 1943                                        .await
 1944                                        .ok()
 1945                                    })
 1946                                    .detach();
 1947                                });
 1948                            }
 1949                        }
 1950                    }
 1951
 1952                    _ => {}
 1953                },
 1954            ));
 1955            if let Some(task_inventory) = project
 1956                .read(cx)
 1957                .task_store()
 1958                .read(cx)
 1959                .task_inventory()
 1960                .cloned()
 1961            {
 1962                project_subscriptions.push(cx.observe_in(
 1963                    &task_inventory,
 1964                    window,
 1965                    |editor, _, window, cx| {
 1966                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1967                    },
 1968                ));
 1969            };
 1970
 1971            project_subscriptions.push(cx.subscribe_in(
 1972                &project.read(cx).breakpoint_store(),
 1973                window,
 1974                |editor, _, event, window, cx| match event {
 1975                    BreakpointStoreEvent::ClearDebugLines => {
 1976                        editor.clear_row_highlights::<ActiveDebugLine>();
 1977                        editor.refresh_inline_values(cx);
 1978                    }
 1979                    BreakpointStoreEvent::SetDebugLine => {
 1980                        if editor.go_to_active_debug_line(window, cx) {
 1981                            cx.stop_propagation();
 1982                        }
 1983
 1984                        editor.refresh_inline_values(cx);
 1985                    }
 1986                    _ => {}
 1987                },
 1988            ));
 1989            let git_store = project.read(cx).git_store().clone();
 1990            let project = project.clone();
 1991            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1992                if let GitStoreEvent::RepositoryUpdated(
 1993                    _,
 1994                    RepositoryEvent::Updated {
 1995                        new_instance: true, ..
 1996                    },
 1997                    _,
 1998                ) = event
 1999                {
 2000                    this.load_diff_task = Some(
 2001                        update_uncommitted_diff_for_buffer(
 2002                            cx.entity(),
 2003                            &project,
 2004                            this.buffer.read(cx).all_buffers(),
 2005                            this.buffer.clone(),
 2006                            cx,
 2007                        )
 2008                        .shared(),
 2009                    );
 2010                }
 2011            }));
 2012        }
 2013
 2014        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2015
 2016        let inlay_hint_settings =
 2017            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2018        let focus_handle = cx.focus_handle();
 2019        if !is_minimap {
 2020            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2021                .detach();
 2022            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2023                .detach();
 2024            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2025                .detach();
 2026            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2027                .detach();
 2028            cx.observe_pending_input(window, Self::observe_pending_input)
 2029                .detach();
 2030        }
 2031
 2032        let show_indent_guides =
 2033            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2034                Some(false)
 2035            } else {
 2036                None
 2037            };
 2038
 2039        let breakpoint_store = match (&mode, project.as_ref()) {
 2040            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2041            _ => None,
 2042        };
 2043
 2044        let mut code_action_providers = Vec::new();
 2045        let mut load_uncommitted_diff = None;
 2046        if let Some(project) = project.clone() {
 2047            load_uncommitted_diff = Some(
 2048                update_uncommitted_diff_for_buffer(
 2049                    cx.entity(),
 2050                    &project,
 2051                    buffer.read(cx).all_buffers(),
 2052                    buffer.clone(),
 2053                    cx,
 2054                )
 2055                .shared(),
 2056            );
 2057            code_action_providers.push(Rc::new(project) as Rc<_>);
 2058        }
 2059
 2060        let mut editor = Self {
 2061            focus_handle,
 2062            show_cursor_when_unfocused: false,
 2063            last_focused_descendant: None,
 2064            buffer: buffer.clone(),
 2065            display_map: display_map.clone(),
 2066            placeholder_display_map: None,
 2067            selections,
 2068            scroll_manager: ScrollManager::new(cx),
 2069            columnar_selection_state: None,
 2070            add_selections_state: None,
 2071            select_next_state: None,
 2072            select_prev_state: None,
 2073            selection_history: SelectionHistory::default(),
 2074            defer_selection_effects: false,
 2075            deferred_selection_effects_state: None,
 2076            autoclose_regions: Vec::new(),
 2077            snippet_stack: InvalidationStack::default(),
 2078            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2079            ime_transaction: None,
 2080            active_diagnostics: ActiveDiagnostic::None,
 2081            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2082            inline_diagnostics_update: Task::ready(()),
 2083            inline_diagnostics: Vec::new(),
 2084            soft_wrap_mode_override,
 2085            diagnostics_max_severity,
 2086            hard_wrap: None,
 2087            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2088            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2089            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2090            project,
 2091            blink_manager: blink_manager.clone(),
 2092            show_local_selections: true,
 2093            show_scrollbars: ScrollbarAxes {
 2094                horizontal: full_mode,
 2095                vertical: full_mode,
 2096            },
 2097            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2098            offset_content: !matches!(mode, EditorMode::SingleLine),
 2099            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2100            show_gutter: full_mode,
 2101            show_line_numbers: (!full_mode).then_some(false),
 2102            use_relative_line_numbers: None,
 2103            disable_expand_excerpt_buttons: !full_mode,
 2104            show_git_diff_gutter: None,
 2105            show_code_actions: None,
 2106            show_runnables: None,
 2107            show_breakpoints: None,
 2108            show_wrap_guides: None,
 2109            show_indent_guides,
 2110            highlight_order: 0,
 2111            highlighted_rows: HashMap::default(),
 2112            background_highlights: HashMap::default(),
 2113            gutter_highlights: HashMap::default(),
 2114            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2115            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2116            nav_history: None,
 2117            context_menu: RefCell::new(None),
 2118            context_menu_options: None,
 2119            mouse_context_menu: None,
 2120            completion_tasks: Vec::new(),
 2121            inline_blame_popover: None,
 2122            inline_blame_popover_show_task: None,
 2123            signature_help_state: SignatureHelpState::default(),
 2124            auto_signature_help: None,
 2125            find_all_references_task_sources: Vec::new(),
 2126            next_completion_id: 0,
 2127            next_inlay_id: 0,
 2128            code_action_providers,
 2129            available_code_actions: None,
 2130            code_actions_task: None,
 2131            quick_selection_highlight_task: None,
 2132            debounced_selection_highlight_task: None,
 2133            document_highlights_task: None,
 2134            linked_editing_range_task: None,
 2135            pending_rename: None,
 2136            searchable: !is_minimap,
 2137            cursor_shape: EditorSettings::get_global(cx)
 2138                .cursor_shape
 2139                .unwrap_or_default(),
 2140            current_line_highlight: None,
 2141            autoindent_mode: Some(AutoindentMode::EachLine),
 2142            collapse_matches: false,
 2143            workspace: None,
 2144            input_enabled: !is_minimap,
 2145            use_modal_editing: full_mode,
 2146            read_only: is_minimap,
 2147            use_autoclose: true,
 2148            use_auto_surround: true,
 2149            auto_replace_emoji_shortcode: false,
 2150            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2151            leader_id: None,
 2152            remote_id: None,
 2153            hover_state: HoverState::default(),
 2154            pending_mouse_down: None,
 2155            hovered_link_state: None,
 2156            edit_prediction_provider: None,
 2157            active_edit_prediction: None,
 2158            stale_edit_prediction_in_menu: None,
 2159            edit_prediction_preview: EditPredictionPreview::Inactive {
 2160                released_too_fast: false,
 2161            },
 2162            inline_diagnostics_enabled: full_mode,
 2163            diagnostics_enabled: full_mode,
 2164            word_completions_enabled: full_mode,
 2165            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2166            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2167            gutter_hovered: false,
 2168            pixel_position_of_newest_cursor: None,
 2169            last_bounds: None,
 2170            last_position_map: None,
 2171            expect_bounds_change: None,
 2172            gutter_dimensions: GutterDimensions::default(),
 2173            style: None,
 2174            show_cursor_names: false,
 2175            hovered_cursors: HashMap::default(),
 2176            next_editor_action_id: EditorActionId::default(),
 2177            editor_actions: Rc::default(),
 2178            edit_predictions_hidden_for_vim_mode: false,
 2179            show_edit_predictions_override: None,
 2180            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2181            edit_prediction_settings: EditPredictionSettings::Disabled,
 2182            edit_prediction_indent_conflict: false,
 2183            edit_prediction_requires_modifier_in_indent_conflict: true,
 2184            custom_context_menu: None,
 2185            show_git_blame_gutter: false,
 2186            show_git_blame_inline: false,
 2187            show_selection_menu: None,
 2188            show_git_blame_inline_delay_task: None,
 2189            git_blame_inline_enabled: full_mode
 2190                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2191            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2192            serialize_dirty_buffers: !is_minimap
 2193                && ProjectSettings::get_global(cx)
 2194                    .session
 2195                    .restore_unsaved_buffers,
 2196            blame: None,
 2197            blame_subscription: None,
 2198            tasks: BTreeMap::default(),
 2199
 2200            breakpoint_store,
 2201            gutter_breakpoint_indicator: (None, None),
 2202            hovered_diff_hunk_row: None,
 2203            _subscriptions: (!is_minimap)
 2204                .then(|| {
 2205                    vec![
 2206                        cx.observe(&buffer, Self::on_buffer_changed),
 2207                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2208                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2209                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2210                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2211                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2212                        cx.observe_window_activation(window, |editor, window, cx| {
 2213                            let active = window.is_window_active();
 2214                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2215                                if active {
 2216                                    blink_manager.enable(cx);
 2217                                } else {
 2218                                    blink_manager.disable(cx);
 2219                                }
 2220                            });
 2221                            if active {
 2222                                editor.show_mouse_cursor(cx);
 2223                            }
 2224                        }),
 2225                    ]
 2226                })
 2227                .unwrap_or_default(),
 2228            tasks_update_task: None,
 2229            pull_diagnostics_task: Task::ready(()),
 2230            colors: None,
 2231            next_color_inlay_id: 0,
 2232            linked_edit_ranges: Default::default(),
 2233            in_project_search: false,
 2234            previous_search_ranges: None,
 2235            breadcrumb_header: None,
 2236            focused_block: None,
 2237            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2238            addons: HashMap::default(),
 2239            registered_buffers: HashMap::default(),
 2240            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2241            selection_mark_mode: false,
 2242            toggle_fold_multiple_buffers: Task::ready(()),
 2243            serialize_selections: Task::ready(()),
 2244            serialize_folds: Task::ready(()),
 2245            text_style_refinement: None,
 2246            load_diff_task: load_uncommitted_diff,
 2247            temporary_diff_override: false,
 2248            mouse_cursor_hidden: false,
 2249            minimap: None,
 2250            hide_mouse_mode: EditorSettings::get_global(cx)
 2251                .hide_mouse
 2252                .unwrap_or_default(),
 2253            change_list: ChangeList::new(),
 2254            mode,
 2255            selection_drag_state: SelectionDragState::None,
 2256            folding_newlines: Task::ready(()),
 2257            lookup_key: None,
 2258        };
 2259
 2260        if is_minimap {
 2261            return editor;
 2262        }
 2263
 2264        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2265            editor
 2266                ._subscriptions
 2267                .push(cx.observe(breakpoints, |_, _, cx| {
 2268                    cx.notify();
 2269                }));
 2270        }
 2271        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2272        editor._subscriptions.extend(project_subscriptions);
 2273
 2274        editor._subscriptions.push(cx.subscribe_in(
 2275            &cx.entity(),
 2276            window,
 2277            |editor, _, e: &EditorEvent, window, cx| match e {
 2278                EditorEvent::ScrollPositionChanged { local, .. } => {
 2279                    if *local {
 2280                        let new_anchor = editor.scroll_manager.anchor();
 2281                        let snapshot = editor.snapshot(window, cx);
 2282                        editor.update_restoration_data(cx, move |data| {
 2283                            data.scroll_position = (
 2284                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2285                                new_anchor.offset,
 2286                            );
 2287                        });
 2288                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2289                        editor.inline_blame_popover.take();
 2290                    }
 2291                }
 2292                EditorEvent::Edited { .. } => {
 2293                    if !vim_enabled(cx) {
 2294                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2295                        let pop_state = editor
 2296                            .change_list
 2297                            .last()
 2298                            .map(|previous| {
 2299                                previous.len() == selections.len()
 2300                                    && previous.iter().enumerate().all(|(ix, p)| {
 2301                                        p.to_display_point(&map).row()
 2302                                            == selections[ix].head().row()
 2303                                    })
 2304                            })
 2305                            .unwrap_or(false);
 2306                        let new_positions = selections
 2307                            .into_iter()
 2308                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2309                            .collect();
 2310                        editor
 2311                            .change_list
 2312                            .push_to_change_list(pop_state, new_positions);
 2313                    }
 2314                }
 2315                _ => (),
 2316            },
 2317        ));
 2318
 2319        if let Some(dap_store) = editor
 2320            .project
 2321            .as_ref()
 2322            .map(|project| project.read(cx).dap_store())
 2323        {
 2324            let weak_editor = cx.weak_entity();
 2325
 2326            editor
 2327                ._subscriptions
 2328                .push(
 2329                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2330                        let session_entity = cx.entity();
 2331                        weak_editor
 2332                            .update(cx, |editor, cx| {
 2333                                editor._subscriptions.push(
 2334                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2335                                );
 2336                            })
 2337                            .ok();
 2338                    }),
 2339                );
 2340
 2341            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2342                editor
 2343                    ._subscriptions
 2344                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2345            }
 2346        }
 2347
 2348        // skip adding the initial selection to selection history
 2349        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2350        editor.end_selection(window, cx);
 2351        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2352
 2353        editor.scroll_manager.show_scrollbars(window, cx);
 2354        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2355
 2356        if full_mode {
 2357            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2358            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2359
 2360            if editor.git_blame_inline_enabled {
 2361                editor.start_git_blame_inline(false, window, cx);
 2362            }
 2363
 2364            editor.go_to_active_debug_line(window, cx);
 2365
 2366            if let Some(buffer) = buffer.read(cx).as_singleton()
 2367                && let Some(project) = editor.project()
 2368            {
 2369                let handle = project.update(cx, |project, cx| {
 2370                    project.register_buffer_with_language_servers(&buffer, cx)
 2371                });
 2372                editor
 2373                    .registered_buffers
 2374                    .insert(buffer.read(cx).remote_id(), handle);
 2375            }
 2376
 2377            editor.minimap =
 2378                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2379            editor.colors = Some(LspColorData::new(cx));
 2380            editor.update_lsp_data(false, None, window, cx);
 2381        }
 2382
 2383        if editor.mode.is_full() {
 2384            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2385        }
 2386
 2387        editor
 2388    }
 2389
 2390    pub fn deploy_mouse_context_menu(
 2391        &mut self,
 2392        position: gpui::Point<Pixels>,
 2393        context_menu: Entity<ContextMenu>,
 2394        window: &mut Window,
 2395        cx: &mut Context<Self>,
 2396    ) {
 2397        self.mouse_context_menu = Some(MouseContextMenu::new(
 2398            self,
 2399            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2400            context_menu,
 2401            window,
 2402            cx,
 2403        ));
 2404    }
 2405
 2406    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2407        self.mouse_context_menu
 2408            .as_ref()
 2409            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2410    }
 2411
 2412    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2413        if self
 2414            .selections
 2415            .pending_anchor()
 2416            .is_some_and(|pending_selection| {
 2417                let snapshot = self.buffer().read(cx).snapshot(cx);
 2418                pending_selection.range().includes(range, &snapshot)
 2419            })
 2420        {
 2421            return true;
 2422        }
 2423
 2424        self.selections
 2425            .disjoint_in_range::<usize>(range.clone(), cx)
 2426            .into_iter()
 2427            .any(|selection| {
 2428                // This is needed to cover a corner case, if we just check for an existing
 2429                // selection in the fold range, having a cursor at the start of the fold
 2430                // marks it as selected. Non-empty selections don't cause this.
 2431                let length = selection.end - selection.start;
 2432                length > 0
 2433            })
 2434    }
 2435
 2436    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2437        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2438    }
 2439
 2440    fn key_context_internal(
 2441        &self,
 2442        has_active_edit_prediction: bool,
 2443        window: &Window,
 2444        cx: &App,
 2445    ) -> KeyContext {
 2446        let mut key_context = KeyContext::new_with_defaults();
 2447        key_context.add("Editor");
 2448        let mode = match self.mode {
 2449            EditorMode::SingleLine => "single_line",
 2450            EditorMode::AutoHeight { .. } => "auto_height",
 2451            EditorMode::Minimap { .. } => "minimap",
 2452            EditorMode::Full { .. } => "full",
 2453        };
 2454
 2455        if EditorSettings::jupyter_enabled(cx) {
 2456            key_context.add("jupyter");
 2457        }
 2458
 2459        key_context.set("mode", mode);
 2460        if self.pending_rename.is_some() {
 2461            key_context.add("renaming");
 2462        }
 2463
 2464        match self.context_menu.borrow().as_ref() {
 2465            Some(CodeContextMenu::Completions(menu)) => {
 2466                if menu.visible() {
 2467                    key_context.add("menu");
 2468                    key_context.add("showing_completions");
 2469                }
 2470            }
 2471            Some(CodeContextMenu::CodeActions(menu)) => {
 2472                if menu.visible() {
 2473                    key_context.add("menu");
 2474                    key_context.add("showing_code_actions")
 2475                }
 2476            }
 2477            None => {}
 2478        }
 2479
 2480        if self.signature_help_state.has_multiple_signatures() {
 2481            key_context.add("showing_signature_help");
 2482        }
 2483
 2484        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2485        if !self.focus_handle(cx).contains_focused(window, cx)
 2486            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2487        {
 2488            for addon in self.addons.values() {
 2489                addon.extend_key_context(&mut key_context, cx)
 2490            }
 2491        }
 2492
 2493        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2494            if let Some(extension) = singleton_buffer
 2495                .read(cx)
 2496                .file()
 2497                .and_then(|file| file.path().extension()?.to_str())
 2498            {
 2499                key_context.set("extension", extension.to_string());
 2500            }
 2501        } else {
 2502            key_context.add("multibuffer");
 2503        }
 2504
 2505        if has_active_edit_prediction {
 2506            if self.edit_prediction_in_conflict() {
 2507                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2508            } else {
 2509                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2510                key_context.add("copilot_suggestion");
 2511            }
 2512        }
 2513
 2514        if self.selection_mark_mode {
 2515            key_context.add("selection_mode");
 2516        }
 2517
 2518        key_context
 2519    }
 2520
 2521    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2522        if self.mouse_cursor_hidden {
 2523            self.mouse_cursor_hidden = false;
 2524            cx.notify();
 2525        }
 2526    }
 2527
 2528    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2529        let hide_mouse_cursor = match origin {
 2530            HideMouseCursorOrigin::TypingAction => {
 2531                matches!(
 2532                    self.hide_mouse_mode,
 2533                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2534                )
 2535            }
 2536            HideMouseCursorOrigin::MovementAction => {
 2537                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2538            }
 2539        };
 2540        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2541            self.mouse_cursor_hidden = hide_mouse_cursor;
 2542            cx.notify();
 2543        }
 2544    }
 2545
 2546    pub fn edit_prediction_in_conflict(&self) -> bool {
 2547        if !self.show_edit_predictions_in_menu() {
 2548            return false;
 2549        }
 2550
 2551        let showing_completions = self
 2552            .context_menu
 2553            .borrow()
 2554            .as_ref()
 2555            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2556
 2557        showing_completions
 2558            || self.edit_prediction_requires_modifier()
 2559            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2560            // bindings to insert tab characters.
 2561            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2562    }
 2563
 2564    pub fn accept_edit_prediction_keybind(
 2565        &self,
 2566        accept_partial: bool,
 2567        window: &Window,
 2568        cx: &App,
 2569    ) -> AcceptEditPredictionBinding {
 2570        let key_context = self.key_context_internal(true, window, cx);
 2571        let in_conflict = self.edit_prediction_in_conflict();
 2572
 2573        let bindings = if accept_partial {
 2574            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2575        } else {
 2576            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2577        };
 2578
 2579        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2580        // just the first one.
 2581        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2582            !in_conflict
 2583                || binding
 2584                    .keystrokes()
 2585                    .first()
 2586                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2587        }))
 2588    }
 2589
 2590    pub fn new_file(
 2591        workspace: &mut Workspace,
 2592        _: &workspace::NewFile,
 2593        window: &mut Window,
 2594        cx: &mut Context<Workspace>,
 2595    ) {
 2596        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2597            "Failed to create buffer",
 2598            window,
 2599            cx,
 2600            |e, _, _| match e.error_code() {
 2601                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2602                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2603                e.error_tag("required").unwrap_or("the latest version")
 2604            )),
 2605                _ => None,
 2606            },
 2607        );
 2608    }
 2609
 2610    pub fn new_in_workspace(
 2611        workspace: &mut Workspace,
 2612        window: &mut Window,
 2613        cx: &mut Context<Workspace>,
 2614    ) -> Task<Result<Entity<Editor>>> {
 2615        let project = workspace.project().clone();
 2616        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2617
 2618        cx.spawn_in(window, async move |workspace, cx| {
 2619            let buffer = create.await?;
 2620            workspace.update_in(cx, |workspace, window, cx| {
 2621                let editor =
 2622                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2623                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2624                editor
 2625            })
 2626        })
 2627    }
 2628
 2629    fn new_file_vertical(
 2630        workspace: &mut Workspace,
 2631        _: &workspace::NewFileSplitVertical,
 2632        window: &mut Window,
 2633        cx: &mut Context<Workspace>,
 2634    ) {
 2635        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2636    }
 2637
 2638    fn new_file_horizontal(
 2639        workspace: &mut Workspace,
 2640        _: &workspace::NewFileSplitHorizontal,
 2641        window: &mut Window,
 2642        cx: &mut Context<Workspace>,
 2643    ) {
 2644        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2645    }
 2646
 2647    fn new_file_in_direction(
 2648        workspace: &mut Workspace,
 2649        direction: SplitDirection,
 2650        window: &mut Window,
 2651        cx: &mut Context<Workspace>,
 2652    ) {
 2653        let project = workspace.project().clone();
 2654        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2655
 2656        cx.spawn_in(window, async move |workspace, cx| {
 2657            let buffer = create.await?;
 2658            workspace.update_in(cx, move |workspace, window, cx| {
 2659                workspace.split_item(
 2660                    direction,
 2661                    Box::new(
 2662                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2663                    ),
 2664                    window,
 2665                    cx,
 2666                )
 2667            })?;
 2668            anyhow::Ok(())
 2669        })
 2670        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2671            match e.error_code() {
 2672                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2673                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2674                e.error_tag("required").unwrap_or("the latest version")
 2675            )),
 2676                _ => None,
 2677            }
 2678        });
 2679    }
 2680
 2681    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2682        self.leader_id
 2683    }
 2684
 2685    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2686        &self.buffer
 2687    }
 2688
 2689    pub fn project(&self) -> Option<&Entity<Project>> {
 2690        self.project.as_ref()
 2691    }
 2692
 2693    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2694        self.workspace.as_ref()?.0.upgrade()
 2695    }
 2696
 2697    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2698        self.buffer().read(cx).title(cx)
 2699    }
 2700
 2701    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2702        let git_blame_gutter_max_author_length = self
 2703            .render_git_blame_gutter(cx)
 2704            .then(|| {
 2705                if let Some(blame) = self.blame.as_ref() {
 2706                    let max_author_length =
 2707                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2708                    Some(max_author_length)
 2709                } else {
 2710                    None
 2711                }
 2712            })
 2713            .flatten();
 2714
 2715        EditorSnapshot {
 2716            mode: self.mode.clone(),
 2717            show_gutter: self.show_gutter,
 2718            show_line_numbers: self.show_line_numbers,
 2719            show_git_diff_gutter: self.show_git_diff_gutter,
 2720            show_code_actions: self.show_code_actions,
 2721            show_runnables: self.show_runnables,
 2722            show_breakpoints: self.show_breakpoints,
 2723            git_blame_gutter_max_author_length,
 2724            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2725            placeholder_display_snapshot: self
 2726                .placeholder_display_map
 2727                .as_ref()
 2728                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2729            scroll_anchor: self.scroll_manager.anchor(),
 2730            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2731            is_focused: self.focus_handle.is_focused(window),
 2732            current_line_highlight: self
 2733                .current_line_highlight
 2734                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2735            gutter_hovered: self.gutter_hovered,
 2736        }
 2737    }
 2738
 2739    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2740        self.buffer.read(cx).language_at(point, cx)
 2741    }
 2742
 2743    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2744        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2745    }
 2746
 2747    pub fn active_excerpt(
 2748        &self,
 2749        cx: &App,
 2750    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2751        self.buffer
 2752            .read(cx)
 2753            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2754    }
 2755
 2756    pub fn mode(&self) -> &EditorMode {
 2757        &self.mode
 2758    }
 2759
 2760    pub fn set_mode(&mut self, mode: EditorMode) {
 2761        self.mode = mode;
 2762    }
 2763
 2764    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2765        self.collaboration_hub.as_deref()
 2766    }
 2767
 2768    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2769        self.collaboration_hub = Some(hub);
 2770    }
 2771
 2772    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2773        self.in_project_search = in_project_search;
 2774    }
 2775
 2776    pub fn set_custom_context_menu(
 2777        &mut self,
 2778        f: impl 'static
 2779        + Fn(
 2780            &mut Self,
 2781            DisplayPoint,
 2782            &mut Window,
 2783            &mut Context<Self>,
 2784        ) -> Option<Entity<ui::ContextMenu>>,
 2785    ) {
 2786        self.custom_context_menu = Some(Box::new(f))
 2787    }
 2788
 2789    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2790        self.completion_provider = provider;
 2791    }
 2792
 2793    #[cfg(any(test, feature = "test-support"))]
 2794    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2795        self.completion_provider.clone()
 2796    }
 2797
 2798    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2799        self.semantics_provider.clone()
 2800    }
 2801
 2802    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2803        self.semantics_provider = provider;
 2804    }
 2805
 2806    pub fn set_edit_prediction_provider<T>(
 2807        &mut self,
 2808        provider: Option<Entity<T>>,
 2809        window: &mut Window,
 2810        cx: &mut Context<Self>,
 2811    ) where
 2812        T: EditPredictionProvider,
 2813    {
 2814        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2815            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2816                if this.focus_handle.is_focused(window) {
 2817                    this.update_visible_edit_prediction(window, cx);
 2818                }
 2819            }),
 2820            provider: Arc::new(provider),
 2821        });
 2822        self.update_edit_prediction_settings(cx);
 2823        self.refresh_edit_prediction(false, false, window, cx);
 2824    }
 2825
 2826    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2827        self.placeholder_display_map
 2828            .as_ref()
 2829            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2830    }
 2831
 2832    pub fn set_placeholder_text(
 2833        &mut self,
 2834        placeholder_text: &str,
 2835        window: &mut Window,
 2836        cx: &mut Context<Self>,
 2837    ) {
 2838        let multibuffer = cx
 2839            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2840
 2841        let style = window.text_style();
 2842
 2843        self.placeholder_display_map = Some(cx.new(|cx| {
 2844            DisplayMap::new(
 2845                multibuffer,
 2846                style.font(),
 2847                style.font_size.to_pixels(window.rem_size()),
 2848                None,
 2849                FILE_HEADER_HEIGHT,
 2850                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2851                Default::default(),
 2852                DiagnosticSeverity::Off,
 2853                cx,
 2854            )
 2855        }));
 2856        cx.notify();
 2857    }
 2858
 2859    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2860        self.cursor_shape = cursor_shape;
 2861
 2862        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2863        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2864
 2865        cx.notify();
 2866    }
 2867
 2868    pub fn set_current_line_highlight(
 2869        &mut self,
 2870        current_line_highlight: Option<CurrentLineHighlight>,
 2871    ) {
 2872        self.current_line_highlight = current_line_highlight;
 2873    }
 2874
 2875    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2876        self.collapse_matches = collapse_matches;
 2877    }
 2878
 2879    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2880        let buffers = self.buffer.read(cx).all_buffers();
 2881        let Some(project) = self.project.as_ref() else {
 2882            return;
 2883        };
 2884        project.update(cx, |project, cx| {
 2885            for buffer in buffers {
 2886                self.registered_buffers
 2887                    .entry(buffer.read(cx).remote_id())
 2888                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2889            }
 2890        })
 2891    }
 2892
 2893    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2894        if self.collapse_matches {
 2895            return range.start..range.start;
 2896        }
 2897        range.clone()
 2898    }
 2899
 2900    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2901        if self.display_map.read(cx).clip_at_line_ends != clip {
 2902            self.display_map
 2903                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2904        }
 2905    }
 2906
 2907    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2908        self.input_enabled = input_enabled;
 2909    }
 2910
 2911    pub fn set_edit_predictions_hidden_for_vim_mode(
 2912        &mut self,
 2913        hidden: bool,
 2914        window: &mut Window,
 2915        cx: &mut Context<Self>,
 2916    ) {
 2917        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2918            self.edit_predictions_hidden_for_vim_mode = hidden;
 2919            if hidden {
 2920                self.update_visible_edit_prediction(window, cx);
 2921            } else {
 2922                self.refresh_edit_prediction(true, false, window, cx);
 2923            }
 2924        }
 2925    }
 2926
 2927    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2928        self.menu_edit_predictions_policy = value;
 2929    }
 2930
 2931    pub fn set_autoindent(&mut self, autoindent: bool) {
 2932        if autoindent {
 2933            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2934        } else {
 2935            self.autoindent_mode = None;
 2936        }
 2937    }
 2938
 2939    pub fn read_only(&self, cx: &App) -> bool {
 2940        self.read_only || self.buffer.read(cx).read_only()
 2941    }
 2942
 2943    pub fn set_read_only(&mut self, read_only: bool) {
 2944        self.read_only = read_only;
 2945    }
 2946
 2947    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2948        self.use_autoclose = autoclose;
 2949    }
 2950
 2951    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2952        self.use_auto_surround = auto_surround;
 2953    }
 2954
 2955    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2956        self.auto_replace_emoji_shortcode = auto_replace;
 2957    }
 2958
 2959    pub fn toggle_edit_predictions(
 2960        &mut self,
 2961        _: &ToggleEditPrediction,
 2962        window: &mut Window,
 2963        cx: &mut Context<Self>,
 2964    ) {
 2965        if self.show_edit_predictions_override.is_some() {
 2966            self.set_show_edit_predictions(None, window, cx);
 2967        } else {
 2968            let show_edit_predictions = !self.edit_predictions_enabled();
 2969            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2970        }
 2971    }
 2972
 2973    pub fn set_show_edit_predictions(
 2974        &mut self,
 2975        show_edit_predictions: Option<bool>,
 2976        window: &mut Window,
 2977        cx: &mut Context<Self>,
 2978    ) {
 2979        self.show_edit_predictions_override = show_edit_predictions;
 2980        self.update_edit_prediction_settings(cx);
 2981
 2982        if let Some(false) = show_edit_predictions {
 2983            self.discard_edit_prediction(false, cx);
 2984        } else {
 2985            self.refresh_edit_prediction(false, true, window, cx);
 2986        }
 2987    }
 2988
 2989    fn edit_predictions_disabled_in_scope(
 2990        &self,
 2991        buffer: &Entity<Buffer>,
 2992        buffer_position: language::Anchor,
 2993        cx: &App,
 2994    ) -> bool {
 2995        let snapshot = buffer.read(cx).snapshot();
 2996        let settings = snapshot.settings_at(buffer_position, cx);
 2997
 2998        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2999            return false;
 3000        };
 3001
 3002        scope.override_name().is_some_and(|scope_name| {
 3003            settings
 3004                .edit_predictions_disabled_in
 3005                .iter()
 3006                .any(|s| s == scope_name)
 3007        })
 3008    }
 3009
 3010    pub fn set_use_modal_editing(&mut self, to: bool) {
 3011        self.use_modal_editing = to;
 3012    }
 3013
 3014    pub fn use_modal_editing(&self) -> bool {
 3015        self.use_modal_editing
 3016    }
 3017
 3018    fn selections_did_change(
 3019        &mut self,
 3020        local: bool,
 3021        old_cursor_position: &Anchor,
 3022        effects: SelectionEffects,
 3023        window: &mut Window,
 3024        cx: &mut Context<Self>,
 3025    ) {
 3026        window.invalidate_character_coordinates();
 3027
 3028        // Copy selections to primary selection buffer
 3029        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3030        if local {
 3031            let selections = self.selections.all::<usize>(cx);
 3032            let buffer_handle = self.buffer.read(cx).read(cx);
 3033
 3034            let mut text = String::new();
 3035            for (index, selection) in selections.iter().enumerate() {
 3036                let text_for_selection = buffer_handle
 3037                    .text_for_range(selection.start..selection.end)
 3038                    .collect::<String>();
 3039
 3040                text.push_str(&text_for_selection);
 3041                if index != selections.len() - 1 {
 3042                    text.push('\n');
 3043                }
 3044            }
 3045
 3046            if !text.is_empty() {
 3047                cx.write_to_primary(ClipboardItem::new_string(text));
 3048            }
 3049        }
 3050
 3051        let selection_anchors = self.selections.disjoint_anchors_arc();
 3052
 3053        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3054            self.buffer.update(cx, |buffer, cx| {
 3055                buffer.set_active_selections(
 3056                    &selection_anchors,
 3057                    self.selections.line_mode,
 3058                    self.cursor_shape,
 3059                    cx,
 3060                )
 3061            });
 3062        }
 3063        let display_map = self
 3064            .display_map
 3065            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3066        let buffer = &display_map.buffer_snapshot;
 3067        if self.selections.count() == 1 {
 3068            self.add_selections_state = None;
 3069        }
 3070        self.select_next_state = None;
 3071        self.select_prev_state = None;
 3072        self.select_syntax_node_history.try_clear();
 3073        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3074        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3075        self.take_rename(false, window, cx);
 3076
 3077        let newest_selection = self.selections.newest_anchor();
 3078        let new_cursor_position = newest_selection.head();
 3079        let selection_start = newest_selection.start;
 3080
 3081        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3082            self.push_to_nav_history(
 3083                *old_cursor_position,
 3084                Some(new_cursor_position.to_point(buffer)),
 3085                false,
 3086                effects.nav_history == Some(true),
 3087                cx,
 3088            );
 3089        }
 3090
 3091        if local {
 3092            if let Some(buffer_id) = new_cursor_position.buffer_id
 3093                && !self.registered_buffers.contains_key(&buffer_id)
 3094                && let Some(project) = self.project.as_ref()
 3095            {
 3096                project.update(cx, |project, cx| {
 3097                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3098                        return;
 3099                    };
 3100                    self.registered_buffers.insert(
 3101                        buffer_id,
 3102                        project.register_buffer_with_language_servers(&buffer, cx),
 3103                    );
 3104                })
 3105            }
 3106
 3107            let mut context_menu = self.context_menu.borrow_mut();
 3108            let completion_menu = match context_menu.as_ref() {
 3109                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3110                Some(CodeContextMenu::CodeActions(_)) => {
 3111                    *context_menu = None;
 3112                    None
 3113                }
 3114                None => None,
 3115            };
 3116            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3117            drop(context_menu);
 3118
 3119            if effects.completions
 3120                && let Some(completion_position) = completion_position
 3121            {
 3122                let start_offset = selection_start.to_offset(buffer);
 3123                let position_matches = start_offset == completion_position.to_offset(buffer);
 3124                let continue_showing = if position_matches {
 3125                    if self.snippet_stack.is_empty() {
 3126                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3127                    } else {
 3128                        // Snippet choices can be shown even when the cursor is in whitespace.
 3129                        // Dismissing the menu with actions like backspace is handled by
 3130                        // invalidation regions.
 3131                        true
 3132                    }
 3133                } else {
 3134                    false
 3135                };
 3136
 3137                if continue_showing {
 3138                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3139                } else {
 3140                    self.hide_context_menu(window, cx);
 3141                }
 3142            }
 3143
 3144            hide_hover(self, cx);
 3145
 3146            if old_cursor_position.to_display_point(&display_map).row()
 3147                != new_cursor_position.to_display_point(&display_map).row()
 3148            {
 3149                self.available_code_actions.take();
 3150            }
 3151            self.refresh_code_actions(window, cx);
 3152            self.refresh_document_highlights(cx);
 3153            self.refresh_selected_text_highlights(false, window, cx);
 3154            refresh_matching_bracket_highlights(self, window, cx);
 3155            self.update_visible_edit_prediction(window, cx);
 3156            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3157            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3158            self.inline_blame_popover.take();
 3159            if self.git_blame_inline_enabled {
 3160                self.start_inline_blame_timer(window, cx);
 3161            }
 3162        }
 3163
 3164        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3165        cx.emit(EditorEvent::SelectionsChanged { local });
 3166
 3167        let selections = &self.selections.disjoint_anchors_arc();
 3168        if selections.len() == 1 {
 3169            cx.emit(SearchEvent::ActiveMatchChanged)
 3170        }
 3171        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3172            let inmemory_selections = selections
 3173                .iter()
 3174                .map(|s| {
 3175                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3176                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3177                })
 3178                .collect();
 3179            self.update_restoration_data(cx, |data| {
 3180                data.selections = inmemory_selections;
 3181            });
 3182
 3183            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3184                && let Some(workspace_id) =
 3185                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3186            {
 3187                let snapshot = self.buffer().read(cx).snapshot(cx);
 3188                let selections = selections.clone();
 3189                let background_executor = cx.background_executor().clone();
 3190                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3191                self.serialize_selections = cx.background_spawn(async move {
 3192                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3193                            let db_selections = selections
 3194                                .iter()
 3195                                .map(|selection| {
 3196                                    (
 3197                                        selection.start.to_offset(&snapshot),
 3198                                        selection.end.to_offset(&snapshot),
 3199                                    )
 3200                                })
 3201                                .collect();
 3202
 3203                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3204                                .await
 3205                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3206                                .log_err();
 3207                        });
 3208            }
 3209        }
 3210
 3211        cx.notify();
 3212    }
 3213
 3214    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3215        use text::ToOffset as _;
 3216        use text::ToPoint as _;
 3217
 3218        if self.mode.is_minimap()
 3219            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3220        {
 3221            return;
 3222        }
 3223
 3224        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3225            return;
 3226        };
 3227
 3228        let snapshot = singleton.read(cx).snapshot();
 3229        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3230            let display_snapshot = display_map.snapshot(cx);
 3231
 3232            display_snapshot
 3233                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3234                .map(|fold| {
 3235                    fold.range.start.text_anchor.to_point(&snapshot)
 3236                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3237                })
 3238                .collect()
 3239        });
 3240        self.update_restoration_data(cx, |data| {
 3241            data.folds = inmemory_folds;
 3242        });
 3243
 3244        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3245            return;
 3246        };
 3247        let background_executor = cx.background_executor().clone();
 3248        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3249        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3250            display_map
 3251                .snapshot(cx)
 3252                .folds_in_range(0..snapshot.len())
 3253                .map(|fold| {
 3254                    (
 3255                        fold.range.start.text_anchor.to_offset(&snapshot),
 3256                        fold.range.end.text_anchor.to_offset(&snapshot),
 3257                    )
 3258                })
 3259                .collect()
 3260        });
 3261        self.serialize_folds = cx.background_spawn(async move {
 3262            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3263            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3264                .await
 3265                .with_context(|| {
 3266                    format!(
 3267                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3268                    )
 3269                })
 3270                .log_err();
 3271        });
 3272    }
 3273
 3274    pub fn sync_selections(
 3275        &mut self,
 3276        other: Entity<Editor>,
 3277        cx: &mut Context<Self>,
 3278    ) -> gpui::Subscription {
 3279        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3280        self.selections.change_with(cx, |selections| {
 3281            selections.select_anchors(other_selections);
 3282        });
 3283
 3284        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3285            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3286                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3287                if other_selections.is_empty() {
 3288                    return;
 3289                }
 3290                this.selections.change_with(cx, |selections| {
 3291                    selections.select_anchors(other_selections);
 3292                });
 3293            }
 3294        });
 3295
 3296        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3297            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3298                let these_selections = this.selections.disjoint_anchors().to_vec();
 3299                if these_selections.is_empty() {
 3300                    return;
 3301                }
 3302                other.update(cx, |other_editor, cx| {
 3303                    other_editor.selections.change_with(cx, |selections| {
 3304                        selections.select_anchors(these_selections);
 3305                    })
 3306                });
 3307            }
 3308        });
 3309
 3310        Subscription::join(other_subscription, this_subscription)
 3311    }
 3312
 3313    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3314    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3315    /// effects of selection change occur at the end of the transaction.
 3316    pub fn change_selections<R>(
 3317        &mut self,
 3318        effects: SelectionEffects,
 3319        window: &mut Window,
 3320        cx: &mut Context<Self>,
 3321        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3322    ) -> R {
 3323        if let Some(state) = &mut self.deferred_selection_effects_state {
 3324            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3325            state.effects.completions = effects.completions;
 3326            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3327            let (changed, result) = self.selections.change_with(cx, change);
 3328            state.changed |= changed;
 3329            return result;
 3330        }
 3331        let mut state = DeferredSelectionEffectsState {
 3332            changed: false,
 3333            effects,
 3334            old_cursor_position: self.selections.newest_anchor().head(),
 3335            history_entry: SelectionHistoryEntry {
 3336                selections: self.selections.disjoint_anchors_arc(),
 3337                select_next_state: self.select_next_state.clone(),
 3338                select_prev_state: self.select_prev_state.clone(),
 3339                add_selections_state: self.add_selections_state.clone(),
 3340            },
 3341        };
 3342        let (changed, result) = self.selections.change_with(cx, change);
 3343        state.changed = state.changed || changed;
 3344        if self.defer_selection_effects {
 3345            self.deferred_selection_effects_state = Some(state);
 3346        } else {
 3347            self.apply_selection_effects(state, window, cx);
 3348        }
 3349        result
 3350    }
 3351
 3352    /// Defers the effects of selection change, so that the effects of multiple calls to
 3353    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3354    /// to selection history and the state of popovers based on selection position aren't
 3355    /// erroneously updated.
 3356    pub fn with_selection_effects_deferred<R>(
 3357        &mut self,
 3358        window: &mut Window,
 3359        cx: &mut Context<Self>,
 3360        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3361    ) -> R {
 3362        let already_deferred = self.defer_selection_effects;
 3363        self.defer_selection_effects = true;
 3364        let result = update(self, window, cx);
 3365        if !already_deferred {
 3366            self.defer_selection_effects = false;
 3367            if let Some(state) = self.deferred_selection_effects_state.take() {
 3368                self.apply_selection_effects(state, window, cx);
 3369            }
 3370        }
 3371        result
 3372    }
 3373
 3374    fn apply_selection_effects(
 3375        &mut self,
 3376        state: DeferredSelectionEffectsState,
 3377        window: &mut Window,
 3378        cx: &mut Context<Self>,
 3379    ) {
 3380        if state.changed {
 3381            self.selection_history.push(state.history_entry);
 3382
 3383            if let Some(autoscroll) = state.effects.scroll {
 3384                self.request_autoscroll(autoscroll, cx);
 3385            }
 3386
 3387            let old_cursor_position = &state.old_cursor_position;
 3388
 3389            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3390
 3391            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3392                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3393            }
 3394        }
 3395    }
 3396
 3397    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3398    where
 3399        I: IntoIterator<Item = (Range<S>, T)>,
 3400        S: ToOffset,
 3401        T: Into<Arc<str>>,
 3402    {
 3403        if self.read_only(cx) {
 3404            return;
 3405        }
 3406
 3407        self.buffer
 3408            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3409    }
 3410
 3411    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3412    where
 3413        I: IntoIterator<Item = (Range<S>, T)>,
 3414        S: ToOffset,
 3415        T: Into<Arc<str>>,
 3416    {
 3417        if self.read_only(cx) {
 3418            return;
 3419        }
 3420
 3421        self.buffer.update(cx, |buffer, cx| {
 3422            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3423        });
 3424    }
 3425
 3426    pub fn edit_with_block_indent<I, S, T>(
 3427        &mut self,
 3428        edits: I,
 3429        original_indent_columns: Vec<Option<u32>>,
 3430        cx: &mut Context<Self>,
 3431    ) where
 3432        I: IntoIterator<Item = (Range<S>, T)>,
 3433        S: ToOffset,
 3434        T: Into<Arc<str>>,
 3435    {
 3436        if self.read_only(cx) {
 3437            return;
 3438        }
 3439
 3440        self.buffer.update(cx, |buffer, cx| {
 3441            buffer.edit(
 3442                edits,
 3443                Some(AutoindentMode::Block {
 3444                    original_indent_columns,
 3445                }),
 3446                cx,
 3447            )
 3448        });
 3449    }
 3450
 3451    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3452        self.hide_context_menu(window, cx);
 3453
 3454        match phase {
 3455            SelectPhase::Begin {
 3456                position,
 3457                add,
 3458                click_count,
 3459            } => self.begin_selection(position, add, click_count, window, cx),
 3460            SelectPhase::BeginColumnar {
 3461                position,
 3462                goal_column,
 3463                reset,
 3464                mode,
 3465            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3466            SelectPhase::Extend {
 3467                position,
 3468                click_count,
 3469            } => self.extend_selection(position, click_count, window, cx),
 3470            SelectPhase::Update {
 3471                position,
 3472                goal_column,
 3473                scroll_delta,
 3474            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3475            SelectPhase::End => self.end_selection(window, cx),
 3476        }
 3477    }
 3478
 3479    fn extend_selection(
 3480        &mut self,
 3481        position: DisplayPoint,
 3482        click_count: usize,
 3483        window: &mut Window,
 3484        cx: &mut Context<Self>,
 3485    ) {
 3486        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3487        let tail = self.selections.newest::<usize>(cx).tail();
 3488        self.begin_selection(position, false, click_count, window, cx);
 3489
 3490        let position = position.to_offset(&display_map, Bias::Left);
 3491        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3492
 3493        let mut pending_selection = self
 3494            .selections
 3495            .pending_anchor()
 3496            .cloned()
 3497            .expect("extend_selection not called with pending selection");
 3498        if position >= tail {
 3499            pending_selection.start = tail_anchor;
 3500        } else {
 3501            pending_selection.end = tail_anchor;
 3502            pending_selection.reversed = true;
 3503        }
 3504
 3505        let mut pending_mode = self.selections.pending_mode().unwrap();
 3506        match &mut pending_mode {
 3507            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3508            _ => {}
 3509        }
 3510
 3511        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3512            SelectionEffects::scroll(Autoscroll::fit())
 3513        } else {
 3514            SelectionEffects::no_scroll()
 3515        };
 3516
 3517        self.change_selections(effects, window, cx, |s| {
 3518            s.set_pending(pending_selection.clone(), pending_mode)
 3519        });
 3520    }
 3521
 3522    fn begin_selection(
 3523        &mut self,
 3524        position: DisplayPoint,
 3525        add: bool,
 3526        click_count: usize,
 3527        window: &mut Window,
 3528        cx: &mut Context<Self>,
 3529    ) {
 3530        if !self.focus_handle.is_focused(window) {
 3531            self.last_focused_descendant = None;
 3532            window.focus(&self.focus_handle);
 3533        }
 3534
 3535        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3536        let buffer = &display_map.buffer_snapshot;
 3537        let position = display_map.clip_point(position, Bias::Left);
 3538
 3539        let start;
 3540        let end;
 3541        let mode;
 3542        let mut auto_scroll;
 3543        match click_count {
 3544            1 => {
 3545                start = buffer.anchor_before(position.to_point(&display_map));
 3546                end = start;
 3547                mode = SelectMode::Character;
 3548                auto_scroll = true;
 3549            }
 3550            2 => {
 3551                let position = display_map
 3552                    .clip_point(position, Bias::Left)
 3553                    .to_offset(&display_map, Bias::Left);
 3554                let (range, _) = buffer.surrounding_word(position, false);
 3555                start = buffer.anchor_before(range.start);
 3556                end = buffer.anchor_before(range.end);
 3557                mode = SelectMode::Word(start..end);
 3558                auto_scroll = true;
 3559            }
 3560            3 => {
 3561                let position = display_map
 3562                    .clip_point(position, Bias::Left)
 3563                    .to_point(&display_map);
 3564                let line_start = display_map.prev_line_boundary(position).0;
 3565                let next_line_start = buffer.clip_point(
 3566                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3567                    Bias::Left,
 3568                );
 3569                start = buffer.anchor_before(line_start);
 3570                end = buffer.anchor_before(next_line_start);
 3571                mode = SelectMode::Line(start..end);
 3572                auto_scroll = true;
 3573            }
 3574            _ => {
 3575                start = buffer.anchor_before(0);
 3576                end = buffer.anchor_before(buffer.len());
 3577                mode = SelectMode::All;
 3578                auto_scroll = false;
 3579            }
 3580        }
 3581        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3582
 3583        let point_to_delete: Option<usize> = {
 3584            let selected_points: Vec<Selection<Point>> =
 3585                self.selections.disjoint_in_range(start..end, cx);
 3586
 3587            if !add || click_count > 1 {
 3588                None
 3589            } else if !selected_points.is_empty() {
 3590                Some(selected_points[0].id)
 3591            } else {
 3592                let clicked_point_already_selected =
 3593                    self.selections.disjoint_anchors().iter().find(|selection| {
 3594                        selection.start.to_point(buffer) == start.to_point(buffer)
 3595                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3596                    });
 3597
 3598                clicked_point_already_selected.map(|selection| selection.id)
 3599            }
 3600        };
 3601
 3602        let selections_count = self.selections.count();
 3603        let effects = if auto_scroll {
 3604            SelectionEffects::default()
 3605        } else {
 3606            SelectionEffects::no_scroll()
 3607        };
 3608
 3609        self.change_selections(effects, window, cx, |s| {
 3610            if let Some(point_to_delete) = point_to_delete {
 3611                s.delete(point_to_delete);
 3612
 3613                if selections_count == 1 {
 3614                    s.set_pending_anchor_range(start..end, mode);
 3615                }
 3616            } else {
 3617                if !add {
 3618                    s.clear_disjoint();
 3619                }
 3620
 3621                s.set_pending_anchor_range(start..end, mode);
 3622            }
 3623        });
 3624    }
 3625
 3626    fn begin_columnar_selection(
 3627        &mut self,
 3628        position: DisplayPoint,
 3629        goal_column: u32,
 3630        reset: bool,
 3631        mode: ColumnarMode,
 3632        window: &mut Window,
 3633        cx: &mut Context<Self>,
 3634    ) {
 3635        if !self.focus_handle.is_focused(window) {
 3636            self.last_focused_descendant = None;
 3637            window.focus(&self.focus_handle);
 3638        }
 3639
 3640        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3641
 3642        if reset {
 3643            let pointer_position = display_map
 3644                .buffer_snapshot
 3645                .anchor_before(position.to_point(&display_map));
 3646
 3647            self.change_selections(
 3648                SelectionEffects::scroll(Autoscroll::newest()),
 3649                window,
 3650                cx,
 3651                |s| {
 3652                    s.clear_disjoint();
 3653                    s.set_pending_anchor_range(
 3654                        pointer_position..pointer_position,
 3655                        SelectMode::Character,
 3656                    );
 3657                },
 3658            );
 3659        };
 3660
 3661        let tail = self.selections.newest::<Point>(cx).tail();
 3662        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3663        self.columnar_selection_state = match mode {
 3664            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3665                selection_tail: selection_anchor,
 3666                display_point: if reset {
 3667                    if position.column() != goal_column {
 3668                        Some(DisplayPoint::new(position.row(), goal_column))
 3669                    } else {
 3670                        None
 3671                    }
 3672                } else {
 3673                    None
 3674                },
 3675            }),
 3676            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3677                selection_tail: selection_anchor,
 3678            }),
 3679        };
 3680
 3681        if !reset {
 3682            self.select_columns(position, goal_column, &display_map, window, cx);
 3683        }
 3684    }
 3685
 3686    fn update_selection(
 3687        &mut self,
 3688        position: DisplayPoint,
 3689        goal_column: u32,
 3690        scroll_delta: gpui::Point<f32>,
 3691        window: &mut Window,
 3692        cx: &mut Context<Self>,
 3693    ) {
 3694        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3695
 3696        if self.columnar_selection_state.is_some() {
 3697            self.select_columns(position, goal_column, &display_map, window, cx);
 3698        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3699            let buffer = &display_map.buffer_snapshot;
 3700            let head;
 3701            let tail;
 3702            let mode = self.selections.pending_mode().unwrap();
 3703            match &mode {
 3704                SelectMode::Character => {
 3705                    head = position.to_point(&display_map);
 3706                    tail = pending.tail().to_point(buffer);
 3707                }
 3708                SelectMode::Word(original_range) => {
 3709                    let offset = display_map
 3710                        .clip_point(position, Bias::Left)
 3711                        .to_offset(&display_map, Bias::Left);
 3712                    let original_range = original_range.to_offset(buffer);
 3713
 3714                    let head_offset = if buffer.is_inside_word(offset, false)
 3715                        || original_range.contains(&offset)
 3716                    {
 3717                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3718                        if word_range.start < original_range.start {
 3719                            word_range.start
 3720                        } else {
 3721                            word_range.end
 3722                        }
 3723                    } else {
 3724                        offset
 3725                    };
 3726
 3727                    head = head_offset.to_point(buffer);
 3728                    if head_offset <= original_range.start {
 3729                        tail = original_range.end.to_point(buffer);
 3730                    } else {
 3731                        tail = original_range.start.to_point(buffer);
 3732                    }
 3733                }
 3734                SelectMode::Line(original_range) => {
 3735                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3736
 3737                    let position = display_map
 3738                        .clip_point(position, Bias::Left)
 3739                        .to_point(&display_map);
 3740                    let line_start = display_map.prev_line_boundary(position).0;
 3741                    let next_line_start = buffer.clip_point(
 3742                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3743                        Bias::Left,
 3744                    );
 3745
 3746                    if line_start < original_range.start {
 3747                        head = line_start
 3748                    } else {
 3749                        head = next_line_start
 3750                    }
 3751
 3752                    if head <= original_range.start {
 3753                        tail = original_range.end;
 3754                    } else {
 3755                        tail = original_range.start;
 3756                    }
 3757                }
 3758                SelectMode::All => {
 3759                    return;
 3760                }
 3761            };
 3762
 3763            if head < tail {
 3764                pending.start = buffer.anchor_before(head);
 3765                pending.end = buffer.anchor_before(tail);
 3766                pending.reversed = true;
 3767            } else {
 3768                pending.start = buffer.anchor_before(tail);
 3769                pending.end = buffer.anchor_before(head);
 3770                pending.reversed = false;
 3771            }
 3772
 3773            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3774                s.set_pending(pending.clone(), mode);
 3775            });
 3776        } else {
 3777            log::error!("update_selection dispatched with no pending selection");
 3778            return;
 3779        }
 3780
 3781        self.apply_scroll_delta(scroll_delta, window, cx);
 3782        cx.notify();
 3783    }
 3784
 3785    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3786        self.columnar_selection_state.take();
 3787        if self.selections.pending_anchor().is_some() {
 3788            let selections = self.selections.all::<usize>(cx);
 3789            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3790                s.select(selections);
 3791                s.clear_pending();
 3792            });
 3793        }
 3794    }
 3795
 3796    fn select_columns(
 3797        &mut self,
 3798        head: DisplayPoint,
 3799        goal_column: u32,
 3800        display_map: &DisplaySnapshot,
 3801        window: &mut Window,
 3802        cx: &mut Context<Self>,
 3803    ) {
 3804        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3805            return;
 3806        };
 3807
 3808        let tail = match columnar_state {
 3809            ColumnarSelectionState::FromMouse {
 3810                selection_tail,
 3811                display_point,
 3812            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3813            ColumnarSelectionState::FromSelection { selection_tail } => {
 3814                selection_tail.to_display_point(display_map)
 3815            }
 3816        };
 3817
 3818        let start_row = cmp::min(tail.row(), head.row());
 3819        let end_row = cmp::max(tail.row(), head.row());
 3820        let start_column = cmp::min(tail.column(), goal_column);
 3821        let end_column = cmp::max(tail.column(), goal_column);
 3822        let reversed = start_column < tail.column();
 3823
 3824        let selection_ranges = (start_row.0..=end_row.0)
 3825            .map(DisplayRow)
 3826            .filter_map(|row| {
 3827                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3828                    || start_column <= display_map.line_len(row))
 3829                    && !display_map.is_block_line(row)
 3830                {
 3831                    let start = display_map
 3832                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3833                        .to_point(display_map);
 3834                    let end = display_map
 3835                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3836                        .to_point(display_map);
 3837                    if reversed {
 3838                        Some(end..start)
 3839                    } else {
 3840                        Some(start..end)
 3841                    }
 3842                } else {
 3843                    None
 3844                }
 3845            })
 3846            .collect::<Vec<_>>();
 3847
 3848        let ranges = match columnar_state {
 3849            ColumnarSelectionState::FromMouse { .. } => {
 3850                let mut non_empty_ranges = selection_ranges
 3851                    .iter()
 3852                    .filter(|selection_range| selection_range.start != selection_range.end)
 3853                    .peekable();
 3854                if non_empty_ranges.peek().is_some() {
 3855                    non_empty_ranges.cloned().collect()
 3856                } else {
 3857                    selection_ranges
 3858                }
 3859            }
 3860            _ => selection_ranges,
 3861        };
 3862
 3863        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3864            s.select_ranges(ranges);
 3865        });
 3866        cx.notify();
 3867    }
 3868
 3869    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3870        self.selections
 3871            .all_adjusted(cx)
 3872            .iter()
 3873            .any(|selection| !selection.is_empty())
 3874    }
 3875
 3876    pub fn has_pending_nonempty_selection(&self) -> bool {
 3877        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3878            Some(Selection { start, end, .. }) => start != end,
 3879            None => false,
 3880        };
 3881
 3882        pending_nonempty_selection
 3883            || (self.columnar_selection_state.is_some()
 3884                && self.selections.disjoint_anchors().len() > 1)
 3885    }
 3886
 3887    pub fn has_pending_selection(&self) -> bool {
 3888        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3889    }
 3890
 3891    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3892        self.selection_mark_mode = false;
 3893        self.selection_drag_state = SelectionDragState::None;
 3894
 3895        if self.clear_expanded_diff_hunks(cx) {
 3896            cx.notify();
 3897            return;
 3898        }
 3899        if self.dismiss_menus_and_popups(true, window, cx) {
 3900            return;
 3901        }
 3902
 3903        if self.mode.is_full()
 3904            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3905        {
 3906            return;
 3907        }
 3908
 3909        cx.propagate();
 3910    }
 3911
 3912    pub fn dismiss_menus_and_popups(
 3913        &mut self,
 3914        is_user_requested: bool,
 3915        window: &mut Window,
 3916        cx: &mut Context<Self>,
 3917    ) -> bool {
 3918        if self.take_rename(false, window, cx).is_some() {
 3919            return true;
 3920        }
 3921
 3922        if hide_hover(self, cx) {
 3923            return true;
 3924        }
 3925
 3926        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3927            return true;
 3928        }
 3929
 3930        if self.hide_context_menu(window, cx).is_some() {
 3931            return true;
 3932        }
 3933
 3934        if self.mouse_context_menu.take().is_some() {
 3935            return true;
 3936        }
 3937
 3938        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3939            return true;
 3940        }
 3941
 3942        if self.snippet_stack.pop().is_some() {
 3943            return true;
 3944        }
 3945
 3946        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3947            self.dismiss_diagnostics(cx);
 3948            return true;
 3949        }
 3950
 3951        false
 3952    }
 3953
 3954    fn linked_editing_ranges_for(
 3955        &self,
 3956        selection: Range<text::Anchor>,
 3957        cx: &App,
 3958    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3959        if self.linked_edit_ranges.is_empty() {
 3960            return None;
 3961        }
 3962        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3963            selection.end.buffer_id.and_then(|end_buffer_id| {
 3964                if selection.start.buffer_id != Some(end_buffer_id) {
 3965                    return None;
 3966                }
 3967                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3968                let snapshot = buffer.read(cx).snapshot();
 3969                self.linked_edit_ranges
 3970                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3971                    .map(|ranges| (ranges, snapshot, buffer))
 3972            })?;
 3973        use text::ToOffset as TO;
 3974        // find offset from the start of current range to current cursor position
 3975        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3976
 3977        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3978        let start_difference = start_offset - start_byte_offset;
 3979        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3980        let end_difference = end_offset - start_byte_offset;
 3981        // Current range has associated linked ranges.
 3982        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3983        for range in linked_ranges.iter() {
 3984            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3985            let end_offset = start_offset + end_difference;
 3986            let start_offset = start_offset + start_difference;
 3987            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3988                continue;
 3989            }
 3990            if self.selections.disjoint_anchor_ranges().any(|s| {
 3991                if s.start.buffer_id != selection.start.buffer_id
 3992                    || s.end.buffer_id != selection.end.buffer_id
 3993                {
 3994                    return false;
 3995                }
 3996                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3997                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3998            }) {
 3999                continue;
 4000            }
 4001            let start = buffer_snapshot.anchor_after(start_offset);
 4002            let end = buffer_snapshot.anchor_after(end_offset);
 4003            linked_edits
 4004                .entry(buffer.clone())
 4005                .or_default()
 4006                .push(start..end);
 4007        }
 4008        Some(linked_edits)
 4009    }
 4010
 4011    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4012        let text: Arc<str> = text.into();
 4013
 4014        if self.read_only(cx) {
 4015            return;
 4016        }
 4017
 4018        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4019
 4020        let selections = self.selections.all_adjusted(cx);
 4021        let mut bracket_inserted = false;
 4022        let mut edits = Vec::new();
 4023        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4024        let mut new_selections = Vec::with_capacity(selections.len());
 4025        let mut new_autoclose_regions = Vec::new();
 4026        let snapshot = self.buffer.read(cx).read(cx);
 4027        let mut clear_linked_edit_ranges = false;
 4028
 4029        for (selection, autoclose_region) in
 4030            self.selections_with_autoclose_regions(selections, &snapshot)
 4031        {
 4032            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4033                // Determine if the inserted text matches the opening or closing
 4034                // bracket of any of this language's bracket pairs.
 4035                let mut bracket_pair = None;
 4036                let mut is_bracket_pair_start = false;
 4037                let mut is_bracket_pair_end = false;
 4038                if !text.is_empty() {
 4039                    let mut bracket_pair_matching_end = None;
 4040                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4041                    //  and they are removing the character that triggered IME popup.
 4042                    for (pair, enabled) in scope.brackets() {
 4043                        if !pair.close && !pair.surround {
 4044                            continue;
 4045                        }
 4046
 4047                        if enabled && pair.start.ends_with(text.as_ref()) {
 4048                            let prefix_len = pair.start.len() - text.len();
 4049                            let preceding_text_matches_prefix = prefix_len == 0
 4050                                || (selection.start.column >= (prefix_len as u32)
 4051                                    && snapshot.contains_str_at(
 4052                                        Point::new(
 4053                                            selection.start.row,
 4054                                            selection.start.column - (prefix_len as u32),
 4055                                        ),
 4056                                        &pair.start[..prefix_len],
 4057                                    ));
 4058                            if preceding_text_matches_prefix {
 4059                                bracket_pair = Some(pair.clone());
 4060                                is_bracket_pair_start = true;
 4061                                break;
 4062                            }
 4063                        }
 4064                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4065                        {
 4066                            // take first bracket pair matching end, but don't break in case a later bracket
 4067                            // pair matches start
 4068                            bracket_pair_matching_end = Some(pair.clone());
 4069                        }
 4070                    }
 4071                    if let Some(end) = bracket_pair_matching_end
 4072                        && bracket_pair.is_none()
 4073                    {
 4074                        bracket_pair = Some(end);
 4075                        is_bracket_pair_end = true;
 4076                    }
 4077                }
 4078
 4079                if let Some(bracket_pair) = bracket_pair {
 4080                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4081                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4082                    let auto_surround =
 4083                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4084                    if selection.is_empty() {
 4085                        if is_bracket_pair_start {
 4086                            // If the inserted text is a suffix of an opening bracket and the
 4087                            // selection is preceded by the rest of the opening bracket, then
 4088                            // insert the closing bracket.
 4089                            let following_text_allows_autoclose = snapshot
 4090                                .chars_at(selection.start)
 4091                                .next()
 4092                                .is_none_or(|c| scope.should_autoclose_before(c));
 4093
 4094                            let preceding_text_allows_autoclose = selection.start.column == 0
 4095                                || snapshot
 4096                                    .reversed_chars_at(selection.start)
 4097                                    .next()
 4098                                    .is_none_or(|c| {
 4099                                        bracket_pair.start != bracket_pair.end
 4100                                            || !snapshot
 4101                                                .char_classifier_at(selection.start)
 4102                                                .is_word(c)
 4103                                    });
 4104
 4105                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4106                                && bracket_pair.start.len() == 1
 4107                            {
 4108                                let target = bracket_pair.start.chars().next().unwrap();
 4109                                let current_line_count = snapshot
 4110                                    .reversed_chars_at(selection.start)
 4111                                    .take_while(|&c| c != '\n')
 4112                                    .filter(|&c| c == target)
 4113                                    .count();
 4114                                current_line_count % 2 == 1
 4115                            } else {
 4116                                false
 4117                            };
 4118
 4119                            if autoclose
 4120                                && bracket_pair.close
 4121                                && following_text_allows_autoclose
 4122                                && preceding_text_allows_autoclose
 4123                                && !is_closing_quote
 4124                            {
 4125                                let anchor = snapshot.anchor_before(selection.end);
 4126                                new_selections.push((selection.map(|_| anchor), text.len()));
 4127                                new_autoclose_regions.push((
 4128                                    anchor,
 4129                                    text.len(),
 4130                                    selection.id,
 4131                                    bracket_pair.clone(),
 4132                                ));
 4133                                edits.push((
 4134                                    selection.range(),
 4135                                    format!("{}{}", text, bracket_pair.end).into(),
 4136                                ));
 4137                                bracket_inserted = true;
 4138                                continue;
 4139                            }
 4140                        }
 4141
 4142                        if let Some(region) = autoclose_region {
 4143                            // If the selection is followed by an auto-inserted closing bracket,
 4144                            // then don't insert that closing bracket again; just move the selection
 4145                            // past the closing bracket.
 4146                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4147                                && text.as_ref() == region.pair.end.as_str()
 4148                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4149                            if should_skip {
 4150                                let anchor = snapshot.anchor_after(selection.end);
 4151                                new_selections
 4152                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4153                                continue;
 4154                            }
 4155                        }
 4156
 4157                        let always_treat_brackets_as_autoclosed = snapshot
 4158                            .language_settings_at(selection.start, cx)
 4159                            .always_treat_brackets_as_autoclosed;
 4160                        if always_treat_brackets_as_autoclosed
 4161                            && is_bracket_pair_end
 4162                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4163                        {
 4164                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4165                            // and the inserted text is a closing bracket and the selection is followed
 4166                            // by the closing bracket then move the selection past the closing bracket.
 4167                            let anchor = snapshot.anchor_after(selection.end);
 4168                            new_selections.push((selection.map(|_| anchor), text.len()));
 4169                            continue;
 4170                        }
 4171                    }
 4172                    // If an opening bracket is 1 character long and is typed while
 4173                    // text is selected, then surround that text with the bracket pair.
 4174                    else if auto_surround
 4175                        && bracket_pair.surround
 4176                        && is_bracket_pair_start
 4177                        && bracket_pair.start.chars().count() == 1
 4178                    {
 4179                        edits.push((selection.start..selection.start, text.clone()));
 4180                        edits.push((
 4181                            selection.end..selection.end,
 4182                            bracket_pair.end.as_str().into(),
 4183                        ));
 4184                        bracket_inserted = true;
 4185                        new_selections.push((
 4186                            Selection {
 4187                                id: selection.id,
 4188                                start: snapshot.anchor_after(selection.start),
 4189                                end: snapshot.anchor_before(selection.end),
 4190                                reversed: selection.reversed,
 4191                                goal: selection.goal,
 4192                            },
 4193                            0,
 4194                        ));
 4195                        continue;
 4196                    }
 4197                }
 4198            }
 4199
 4200            if self.auto_replace_emoji_shortcode
 4201                && selection.is_empty()
 4202                && text.as_ref().ends_with(':')
 4203                && let Some(possible_emoji_short_code) =
 4204                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4205                && !possible_emoji_short_code.is_empty()
 4206                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4207            {
 4208                let emoji_shortcode_start = Point::new(
 4209                    selection.start.row,
 4210                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4211                );
 4212
 4213                // Remove shortcode from buffer
 4214                edits.push((
 4215                    emoji_shortcode_start..selection.start,
 4216                    "".to_string().into(),
 4217                ));
 4218                new_selections.push((
 4219                    Selection {
 4220                        id: selection.id,
 4221                        start: snapshot.anchor_after(emoji_shortcode_start),
 4222                        end: snapshot.anchor_before(selection.start),
 4223                        reversed: selection.reversed,
 4224                        goal: selection.goal,
 4225                    },
 4226                    0,
 4227                ));
 4228
 4229                // Insert emoji
 4230                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4231                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4232                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4233
 4234                continue;
 4235            }
 4236
 4237            // If not handling any auto-close operation, then just replace the selected
 4238            // text with the given input and move the selection to the end of the
 4239            // newly inserted text.
 4240            let anchor = snapshot.anchor_after(selection.end);
 4241            if !self.linked_edit_ranges.is_empty() {
 4242                let start_anchor = snapshot.anchor_before(selection.start);
 4243
 4244                let is_word_char = text.chars().next().is_none_or(|char| {
 4245                    let classifier = snapshot
 4246                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4247                        .ignore_punctuation(true);
 4248                    classifier.is_word(char)
 4249                });
 4250
 4251                if is_word_char {
 4252                    if let Some(ranges) = self
 4253                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4254                    {
 4255                        for (buffer, edits) in ranges {
 4256                            linked_edits
 4257                                .entry(buffer.clone())
 4258                                .or_default()
 4259                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4260                        }
 4261                    }
 4262                } else {
 4263                    clear_linked_edit_ranges = true;
 4264                }
 4265            }
 4266
 4267            new_selections.push((selection.map(|_| anchor), 0));
 4268            edits.push((selection.start..selection.end, text.clone()));
 4269        }
 4270
 4271        drop(snapshot);
 4272
 4273        self.transact(window, cx, |this, window, cx| {
 4274            if clear_linked_edit_ranges {
 4275                this.linked_edit_ranges.clear();
 4276            }
 4277            let initial_buffer_versions =
 4278                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4279
 4280            this.buffer.update(cx, |buffer, cx| {
 4281                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4282            });
 4283            for (buffer, edits) in linked_edits {
 4284                buffer.update(cx, |buffer, cx| {
 4285                    let snapshot = buffer.snapshot();
 4286                    let edits = edits
 4287                        .into_iter()
 4288                        .map(|(range, text)| {
 4289                            use text::ToPoint as TP;
 4290                            let end_point = TP::to_point(&range.end, &snapshot);
 4291                            let start_point = TP::to_point(&range.start, &snapshot);
 4292                            (start_point..end_point, text)
 4293                        })
 4294                        .sorted_by_key(|(range, _)| range.start);
 4295                    buffer.edit(edits, None, cx);
 4296                })
 4297            }
 4298            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4299            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4300            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4301            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4302                .zip(new_selection_deltas)
 4303                .map(|(selection, delta)| Selection {
 4304                    id: selection.id,
 4305                    start: selection.start + delta,
 4306                    end: selection.end + delta,
 4307                    reversed: selection.reversed,
 4308                    goal: SelectionGoal::None,
 4309                })
 4310                .collect::<Vec<_>>();
 4311
 4312            let mut i = 0;
 4313            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4314                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4315                let start = map.buffer_snapshot.anchor_before(position);
 4316                let end = map.buffer_snapshot.anchor_after(position);
 4317                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4318                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4319                        Ordering::Less => i += 1,
 4320                        Ordering::Greater => break,
 4321                        Ordering::Equal => {
 4322                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4323                                Ordering::Less => i += 1,
 4324                                Ordering::Equal => break,
 4325                                Ordering::Greater => break,
 4326                            }
 4327                        }
 4328                    }
 4329                }
 4330                this.autoclose_regions.insert(
 4331                    i,
 4332                    AutocloseRegion {
 4333                        selection_id,
 4334                        range: start..end,
 4335                        pair,
 4336                    },
 4337                );
 4338            }
 4339
 4340            let had_active_edit_prediction = this.has_active_edit_prediction();
 4341            this.change_selections(
 4342                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4343                window,
 4344                cx,
 4345                |s| s.select(new_selections),
 4346            );
 4347
 4348            if !bracket_inserted
 4349                && let Some(on_type_format_task) =
 4350                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4351            {
 4352                on_type_format_task.detach_and_log_err(cx);
 4353            }
 4354
 4355            let editor_settings = EditorSettings::get_global(cx);
 4356            if bracket_inserted
 4357                && (editor_settings.auto_signature_help
 4358                    || editor_settings.show_signature_help_after_edits)
 4359            {
 4360                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4361            }
 4362
 4363            let trigger_in_words =
 4364                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4365            if this.hard_wrap.is_some() {
 4366                let latest: Range<Point> = this.selections.newest(cx).range();
 4367                if latest.is_empty()
 4368                    && this
 4369                        .buffer()
 4370                        .read(cx)
 4371                        .snapshot(cx)
 4372                        .line_len(MultiBufferRow(latest.start.row))
 4373                        == latest.start.column
 4374                {
 4375                    this.rewrap_impl(
 4376                        RewrapOptions {
 4377                            override_language_settings: true,
 4378                            preserve_existing_whitespace: true,
 4379                        },
 4380                        cx,
 4381                    )
 4382                }
 4383            }
 4384            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4385            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4386            this.refresh_edit_prediction(true, false, window, cx);
 4387            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4388        });
 4389    }
 4390
 4391    fn find_possible_emoji_shortcode_at_position(
 4392        snapshot: &MultiBufferSnapshot,
 4393        position: Point,
 4394    ) -> Option<String> {
 4395        let mut chars = Vec::new();
 4396        let mut found_colon = false;
 4397        for char in snapshot.reversed_chars_at(position).take(100) {
 4398            // Found a possible emoji shortcode in the middle of the buffer
 4399            if found_colon {
 4400                if char.is_whitespace() {
 4401                    chars.reverse();
 4402                    return Some(chars.iter().collect());
 4403                }
 4404                // If the previous character is not a whitespace, we are in the middle of a word
 4405                // and we only want to complete the shortcode if the word is made up of other emojis
 4406                let mut containing_word = String::new();
 4407                for ch in snapshot
 4408                    .reversed_chars_at(position)
 4409                    .skip(chars.len() + 1)
 4410                    .take(100)
 4411                {
 4412                    if ch.is_whitespace() {
 4413                        break;
 4414                    }
 4415                    containing_word.push(ch);
 4416                }
 4417                let containing_word = containing_word.chars().rev().collect::<String>();
 4418                if util::word_consists_of_emojis(containing_word.as_str()) {
 4419                    chars.reverse();
 4420                    return Some(chars.iter().collect());
 4421                }
 4422            }
 4423
 4424            if char.is_whitespace() || !char.is_ascii() {
 4425                return None;
 4426            }
 4427            if char == ':' {
 4428                found_colon = true;
 4429            } else {
 4430                chars.push(char);
 4431            }
 4432        }
 4433        // Found a possible emoji shortcode at the beginning of the buffer
 4434        chars.reverse();
 4435        Some(chars.iter().collect())
 4436    }
 4437
 4438    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4439        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4440        self.transact(window, cx, |this, window, cx| {
 4441            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4442                let selections = this.selections.all::<usize>(cx);
 4443                let multi_buffer = this.buffer.read(cx);
 4444                let buffer = multi_buffer.snapshot(cx);
 4445                selections
 4446                    .iter()
 4447                    .map(|selection| {
 4448                        let start_point = selection.start.to_point(&buffer);
 4449                        let mut existing_indent =
 4450                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4451                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4452                        let start = selection.start;
 4453                        let end = selection.end;
 4454                        let selection_is_empty = start == end;
 4455                        let language_scope = buffer.language_scope_at(start);
 4456                        let (
 4457                            comment_delimiter,
 4458                            doc_delimiter,
 4459                            insert_extra_newline,
 4460                            indent_on_newline,
 4461                            indent_on_extra_newline,
 4462                        ) = if let Some(language) = &language_scope {
 4463                            let mut insert_extra_newline =
 4464                                insert_extra_newline_brackets(&buffer, start..end, language)
 4465                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4466
 4467                            // Comment extension on newline is allowed only for cursor selections
 4468                            let comment_delimiter = maybe!({
 4469                                if !selection_is_empty {
 4470                                    return None;
 4471                                }
 4472
 4473                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4474                                    return None;
 4475                                }
 4476
 4477                                let delimiters = language.line_comment_prefixes();
 4478                                let max_len_of_delimiter =
 4479                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4480                                let (snapshot, range) =
 4481                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4482
 4483                                let num_of_whitespaces = snapshot
 4484                                    .chars_for_range(range.clone())
 4485                                    .take_while(|c| c.is_whitespace())
 4486                                    .count();
 4487                                let comment_candidate = snapshot
 4488                                    .chars_for_range(range.clone())
 4489                                    .skip(num_of_whitespaces)
 4490                                    .take(max_len_of_delimiter)
 4491                                    .collect::<String>();
 4492                                let (delimiter, trimmed_len) = delimiters
 4493                                    .iter()
 4494                                    .filter_map(|delimiter| {
 4495                                        let prefix = delimiter.trim_end();
 4496                                        if comment_candidate.starts_with(prefix) {
 4497                                            Some((delimiter, prefix.len()))
 4498                                        } else {
 4499                                            None
 4500                                        }
 4501                                    })
 4502                                    .max_by_key(|(_, len)| *len)?;
 4503
 4504                                if let Some(BlockCommentConfig {
 4505                                    start: block_start, ..
 4506                                }) = language.block_comment()
 4507                                {
 4508                                    let block_start_trimmed = block_start.trim_end();
 4509                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4510                                        let line_content = snapshot
 4511                                            .chars_for_range(range)
 4512                                            .skip(num_of_whitespaces)
 4513                                            .take(block_start_trimmed.len())
 4514                                            .collect::<String>();
 4515
 4516                                        if line_content.starts_with(block_start_trimmed) {
 4517                                            return None;
 4518                                        }
 4519                                    }
 4520                                }
 4521
 4522                                let cursor_is_placed_after_comment_marker =
 4523                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4524                                if cursor_is_placed_after_comment_marker {
 4525                                    Some(delimiter.clone())
 4526                                } else {
 4527                                    None
 4528                                }
 4529                            });
 4530
 4531                            let mut indent_on_newline = IndentSize::spaces(0);
 4532                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4533
 4534                            let doc_delimiter = maybe!({
 4535                                if !selection_is_empty {
 4536                                    return None;
 4537                                }
 4538
 4539                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4540                                    return None;
 4541                                }
 4542
 4543                                let BlockCommentConfig {
 4544                                    start: start_tag,
 4545                                    end: end_tag,
 4546                                    prefix: delimiter,
 4547                                    tab_size: len,
 4548                                } = language.documentation_comment()?;
 4549                                let is_within_block_comment = buffer
 4550                                    .language_scope_at(start_point)
 4551                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4552                                if !is_within_block_comment {
 4553                                    return None;
 4554                                }
 4555
 4556                                let (snapshot, range) =
 4557                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4558
 4559                                let num_of_whitespaces = snapshot
 4560                                    .chars_for_range(range.clone())
 4561                                    .take_while(|c| c.is_whitespace())
 4562                                    .count();
 4563
 4564                                // 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.
 4565                                let column = start_point.column;
 4566                                let cursor_is_after_start_tag = {
 4567                                    let start_tag_len = start_tag.len();
 4568                                    let start_tag_line = snapshot
 4569                                        .chars_for_range(range.clone())
 4570                                        .skip(num_of_whitespaces)
 4571                                        .take(start_tag_len)
 4572                                        .collect::<String>();
 4573                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4574                                        num_of_whitespaces + start_tag_len <= column as usize
 4575                                    } else {
 4576                                        false
 4577                                    }
 4578                                };
 4579
 4580                                let cursor_is_after_delimiter = {
 4581                                    let delimiter_trim = delimiter.trim_end();
 4582                                    let delimiter_line = snapshot
 4583                                        .chars_for_range(range.clone())
 4584                                        .skip(num_of_whitespaces)
 4585                                        .take(delimiter_trim.len())
 4586                                        .collect::<String>();
 4587                                    if delimiter_line.starts_with(delimiter_trim) {
 4588                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4589                                    } else {
 4590                                        false
 4591                                    }
 4592                                };
 4593
 4594                                let cursor_is_before_end_tag_if_exists = {
 4595                                    let mut char_position = 0u32;
 4596                                    let mut end_tag_offset = None;
 4597
 4598                                    'outer: for chunk in snapshot.text_for_range(range) {
 4599                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4600                                            let chars_before_match =
 4601                                                chunk[..byte_pos].chars().count() as u32;
 4602                                            end_tag_offset =
 4603                                                Some(char_position + chars_before_match);
 4604                                            break 'outer;
 4605                                        }
 4606                                        char_position += chunk.chars().count() as u32;
 4607                                    }
 4608
 4609                                    if let Some(end_tag_offset) = end_tag_offset {
 4610                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4611                                        if cursor_is_after_start_tag {
 4612                                            if cursor_is_before_end_tag {
 4613                                                insert_extra_newline = true;
 4614                                            }
 4615                                            let cursor_is_at_start_of_end_tag =
 4616                                                column == end_tag_offset;
 4617                                            if cursor_is_at_start_of_end_tag {
 4618                                                indent_on_extra_newline.len = *len;
 4619                                            }
 4620                                        }
 4621                                        cursor_is_before_end_tag
 4622                                    } else {
 4623                                        true
 4624                                    }
 4625                                };
 4626
 4627                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4628                                    && cursor_is_before_end_tag_if_exists
 4629                                {
 4630                                    if cursor_is_after_start_tag {
 4631                                        indent_on_newline.len = *len;
 4632                                    }
 4633                                    Some(delimiter.clone())
 4634                                } else {
 4635                                    None
 4636                                }
 4637                            });
 4638
 4639                            (
 4640                                comment_delimiter,
 4641                                doc_delimiter,
 4642                                insert_extra_newline,
 4643                                indent_on_newline,
 4644                                indent_on_extra_newline,
 4645                            )
 4646                        } else {
 4647                            (
 4648                                None,
 4649                                None,
 4650                                false,
 4651                                IndentSize::default(),
 4652                                IndentSize::default(),
 4653                            )
 4654                        };
 4655
 4656                        let prevent_auto_indent = doc_delimiter.is_some();
 4657                        let delimiter = comment_delimiter.or(doc_delimiter);
 4658
 4659                        let capacity_for_delimiter =
 4660                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4661                        let mut new_text = String::with_capacity(
 4662                            1 + capacity_for_delimiter
 4663                                + existing_indent.len as usize
 4664                                + indent_on_newline.len as usize
 4665                                + indent_on_extra_newline.len as usize,
 4666                        );
 4667                        new_text.push('\n');
 4668                        new_text.extend(existing_indent.chars());
 4669                        new_text.extend(indent_on_newline.chars());
 4670
 4671                        if let Some(delimiter) = &delimiter {
 4672                            new_text.push_str(delimiter);
 4673                        }
 4674
 4675                        if insert_extra_newline {
 4676                            new_text.push('\n');
 4677                            new_text.extend(existing_indent.chars());
 4678                            new_text.extend(indent_on_extra_newline.chars());
 4679                        }
 4680
 4681                        let anchor = buffer.anchor_after(end);
 4682                        let new_selection = selection.map(|_| anchor);
 4683                        (
 4684                            ((start..end, new_text), prevent_auto_indent),
 4685                            (insert_extra_newline, new_selection),
 4686                        )
 4687                    })
 4688                    .unzip()
 4689            };
 4690
 4691            let mut auto_indent_edits = Vec::new();
 4692            let mut edits = Vec::new();
 4693            for (edit, prevent_auto_indent) in edits_with_flags {
 4694                if prevent_auto_indent {
 4695                    edits.push(edit);
 4696                } else {
 4697                    auto_indent_edits.push(edit);
 4698                }
 4699            }
 4700            if !edits.is_empty() {
 4701                this.edit(edits, cx);
 4702            }
 4703            if !auto_indent_edits.is_empty() {
 4704                this.edit_with_autoindent(auto_indent_edits, cx);
 4705            }
 4706
 4707            let buffer = this.buffer.read(cx).snapshot(cx);
 4708            let new_selections = selection_info
 4709                .into_iter()
 4710                .map(|(extra_newline_inserted, new_selection)| {
 4711                    let mut cursor = new_selection.end.to_point(&buffer);
 4712                    if extra_newline_inserted {
 4713                        cursor.row -= 1;
 4714                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4715                    }
 4716                    new_selection.map(|_| cursor)
 4717                })
 4718                .collect();
 4719
 4720            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4721            this.refresh_edit_prediction(true, false, window, cx);
 4722        });
 4723    }
 4724
 4725    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4726        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4727
 4728        let buffer = self.buffer.read(cx);
 4729        let snapshot = buffer.snapshot(cx);
 4730
 4731        let mut edits = Vec::new();
 4732        let mut rows = Vec::new();
 4733
 4734        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4735            let cursor = selection.head();
 4736            let row = cursor.row;
 4737
 4738            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4739
 4740            let newline = "\n".to_string();
 4741            edits.push((start_of_line..start_of_line, newline));
 4742
 4743            rows.push(row + rows_inserted as u32);
 4744        }
 4745
 4746        self.transact(window, cx, |editor, window, cx| {
 4747            editor.edit(edits, cx);
 4748
 4749            editor.change_selections(Default::default(), window, cx, |s| {
 4750                let mut index = 0;
 4751                s.move_cursors_with(|map, _, _| {
 4752                    let row = rows[index];
 4753                    index += 1;
 4754
 4755                    let point = Point::new(row, 0);
 4756                    let boundary = map.next_line_boundary(point).1;
 4757                    let clipped = map.clip_point(boundary, Bias::Left);
 4758
 4759                    (clipped, SelectionGoal::None)
 4760                });
 4761            });
 4762
 4763            let mut indent_edits = Vec::new();
 4764            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4765            for row in rows {
 4766                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4767                for (row, indent) in indents {
 4768                    if indent.len == 0 {
 4769                        continue;
 4770                    }
 4771
 4772                    let text = match indent.kind {
 4773                        IndentKind::Space => " ".repeat(indent.len as usize),
 4774                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4775                    };
 4776                    let point = Point::new(row.0, 0);
 4777                    indent_edits.push((point..point, text));
 4778                }
 4779            }
 4780            editor.edit(indent_edits, cx);
 4781        });
 4782    }
 4783
 4784    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4785        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4786
 4787        let buffer = self.buffer.read(cx);
 4788        let snapshot = buffer.snapshot(cx);
 4789
 4790        let mut edits = Vec::new();
 4791        let mut rows = Vec::new();
 4792        let mut rows_inserted = 0;
 4793
 4794        for selection in self.selections.all_adjusted(cx) {
 4795            let cursor = selection.head();
 4796            let row = cursor.row;
 4797
 4798            let point = Point::new(row + 1, 0);
 4799            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4800
 4801            let newline = "\n".to_string();
 4802            edits.push((start_of_line..start_of_line, newline));
 4803
 4804            rows_inserted += 1;
 4805            rows.push(row + rows_inserted);
 4806        }
 4807
 4808        self.transact(window, cx, |editor, window, cx| {
 4809            editor.edit(edits, cx);
 4810
 4811            editor.change_selections(Default::default(), window, cx, |s| {
 4812                let mut index = 0;
 4813                s.move_cursors_with(|map, _, _| {
 4814                    let row = rows[index];
 4815                    index += 1;
 4816
 4817                    let point = Point::new(row, 0);
 4818                    let boundary = map.next_line_boundary(point).1;
 4819                    let clipped = map.clip_point(boundary, Bias::Left);
 4820
 4821                    (clipped, SelectionGoal::None)
 4822                });
 4823            });
 4824
 4825            let mut indent_edits = Vec::new();
 4826            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4827            for row in rows {
 4828                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4829                for (row, indent) in indents {
 4830                    if indent.len == 0 {
 4831                        continue;
 4832                    }
 4833
 4834                    let text = match indent.kind {
 4835                        IndentKind::Space => " ".repeat(indent.len as usize),
 4836                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4837                    };
 4838                    let point = Point::new(row.0, 0);
 4839                    indent_edits.push((point..point, text));
 4840                }
 4841            }
 4842            editor.edit(indent_edits, cx);
 4843        });
 4844    }
 4845
 4846    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4847        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4848            original_indent_columns: Vec::new(),
 4849        });
 4850        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4851    }
 4852
 4853    fn insert_with_autoindent_mode(
 4854        &mut self,
 4855        text: &str,
 4856        autoindent_mode: Option<AutoindentMode>,
 4857        window: &mut Window,
 4858        cx: &mut Context<Self>,
 4859    ) {
 4860        if self.read_only(cx) {
 4861            return;
 4862        }
 4863
 4864        let text: Arc<str> = text.into();
 4865        self.transact(window, cx, |this, window, cx| {
 4866            let old_selections = this.selections.all_adjusted(cx);
 4867            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4868                let anchors = {
 4869                    let snapshot = buffer.read(cx);
 4870                    old_selections
 4871                        .iter()
 4872                        .map(|s| {
 4873                            let anchor = snapshot.anchor_after(s.head());
 4874                            s.map(|_| anchor)
 4875                        })
 4876                        .collect::<Vec<_>>()
 4877                };
 4878                buffer.edit(
 4879                    old_selections
 4880                        .iter()
 4881                        .map(|s| (s.start..s.end, text.clone())),
 4882                    autoindent_mode,
 4883                    cx,
 4884                );
 4885                anchors
 4886            });
 4887
 4888            this.change_selections(Default::default(), window, cx, |s| {
 4889                s.select_anchors(selection_anchors);
 4890            });
 4891
 4892            cx.notify();
 4893        });
 4894    }
 4895
 4896    fn trigger_completion_on_input(
 4897        &mut self,
 4898        text: &str,
 4899        trigger_in_words: bool,
 4900        window: &mut Window,
 4901        cx: &mut Context<Self>,
 4902    ) {
 4903        let completions_source = self
 4904            .context_menu
 4905            .borrow()
 4906            .as_ref()
 4907            .and_then(|menu| match menu {
 4908                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4909                CodeContextMenu::CodeActions(_) => None,
 4910            });
 4911
 4912        match completions_source {
 4913            Some(CompletionsMenuSource::Words { .. }) => {
 4914                self.open_or_update_completions_menu(
 4915                    Some(CompletionsMenuSource::Words {
 4916                        ignore_threshold: false,
 4917                    }),
 4918                    None,
 4919                    window,
 4920                    cx,
 4921                );
 4922            }
 4923            Some(CompletionsMenuSource::Normal)
 4924            | Some(CompletionsMenuSource::SnippetChoices)
 4925            | None
 4926                if self.is_completion_trigger(
 4927                    text,
 4928                    trigger_in_words,
 4929                    completions_source.is_some(),
 4930                    cx,
 4931                ) =>
 4932            {
 4933                self.show_completions(
 4934                    &ShowCompletions {
 4935                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4936                    },
 4937                    window,
 4938                    cx,
 4939                )
 4940            }
 4941            _ => {
 4942                self.hide_context_menu(window, cx);
 4943            }
 4944        }
 4945    }
 4946
 4947    fn is_completion_trigger(
 4948        &self,
 4949        text: &str,
 4950        trigger_in_words: bool,
 4951        menu_is_open: bool,
 4952        cx: &mut Context<Self>,
 4953    ) -> bool {
 4954        let position = self.selections.newest_anchor().head();
 4955        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4956            return false;
 4957        };
 4958
 4959        if let Some(completion_provider) = &self.completion_provider {
 4960            completion_provider.is_completion_trigger(
 4961                &buffer,
 4962                position.text_anchor,
 4963                text,
 4964                trigger_in_words,
 4965                menu_is_open,
 4966                cx,
 4967            )
 4968        } else {
 4969            false
 4970        }
 4971    }
 4972
 4973    /// If any empty selections is touching the start of its innermost containing autoclose
 4974    /// region, expand it to select the brackets.
 4975    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4976        let selections = self.selections.all::<usize>(cx);
 4977        let buffer = self.buffer.read(cx).read(cx);
 4978        let new_selections = self
 4979            .selections_with_autoclose_regions(selections, &buffer)
 4980            .map(|(mut selection, region)| {
 4981                if !selection.is_empty() {
 4982                    return selection;
 4983                }
 4984
 4985                if let Some(region) = region {
 4986                    let mut range = region.range.to_offset(&buffer);
 4987                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4988                        range.start -= region.pair.start.len();
 4989                        if buffer.contains_str_at(range.start, &region.pair.start)
 4990                            && buffer.contains_str_at(range.end, &region.pair.end)
 4991                        {
 4992                            range.end += region.pair.end.len();
 4993                            selection.start = range.start;
 4994                            selection.end = range.end;
 4995
 4996                            return selection;
 4997                        }
 4998                    }
 4999                }
 5000
 5001                let always_treat_brackets_as_autoclosed = buffer
 5002                    .language_settings_at(selection.start, cx)
 5003                    .always_treat_brackets_as_autoclosed;
 5004
 5005                if !always_treat_brackets_as_autoclosed {
 5006                    return selection;
 5007                }
 5008
 5009                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5010                    for (pair, enabled) in scope.brackets() {
 5011                        if !enabled || !pair.close {
 5012                            continue;
 5013                        }
 5014
 5015                        if buffer.contains_str_at(selection.start, &pair.end) {
 5016                            let pair_start_len = pair.start.len();
 5017                            if buffer.contains_str_at(
 5018                                selection.start.saturating_sub(pair_start_len),
 5019                                &pair.start,
 5020                            ) {
 5021                                selection.start -= pair_start_len;
 5022                                selection.end += pair.end.len();
 5023
 5024                                return selection;
 5025                            }
 5026                        }
 5027                    }
 5028                }
 5029
 5030                selection
 5031            })
 5032            .collect();
 5033
 5034        drop(buffer);
 5035        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5036            selections.select(new_selections)
 5037        });
 5038    }
 5039
 5040    /// Iterate the given selections, and for each one, find the smallest surrounding
 5041    /// autoclose region. This uses the ordering of the selections and the autoclose
 5042    /// regions to avoid repeated comparisons.
 5043    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5044        &'a self,
 5045        selections: impl IntoIterator<Item = Selection<D>>,
 5046        buffer: &'a MultiBufferSnapshot,
 5047    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5048        let mut i = 0;
 5049        let mut regions = self.autoclose_regions.as_slice();
 5050        selections.into_iter().map(move |selection| {
 5051            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5052
 5053            let mut enclosing = None;
 5054            while let Some(pair_state) = regions.get(i) {
 5055                if pair_state.range.end.to_offset(buffer) < range.start {
 5056                    regions = &regions[i + 1..];
 5057                    i = 0;
 5058                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5059                    break;
 5060                } else {
 5061                    if pair_state.selection_id == selection.id {
 5062                        enclosing = Some(pair_state);
 5063                    }
 5064                    i += 1;
 5065                }
 5066            }
 5067
 5068            (selection, enclosing)
 5069        })
 5070    }
 5071
 5072    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5073    fn invalidate_autoclose_regions(
 5074        &mut self,
 5075        mut selections: &[Selection<Anchor>],
 5076        buffer: &MultiBufferSnapshot,
 5077    ) {
 5078        self.autoclose_regions.retain(|state| {
 5079            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5080                return false;
 5081            }
 5082
 5083            let mut i = 0;
 5084            while let Some(selection) = selections.get(i) {
 5085                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5086                    selections = &selections[1..];
 5087                    continue;
 5088                }
 5089                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5090                    break;
 5091                }
 5092                if selection.id == state.selection_id {
 5093                    return true;
 5094                } else {
 5095                    i += 1;
 5096                }
 5097            }
 5098            false
 5099        });
 5100    }
 5101
 5102    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5103        let offset = position.to_offset(buffer);
 5104        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5105        if offset > word_range.start && kind == Some(CharKind::Word) {
 5106            Some(
 5107                buffer
 5108                    .text_for_range(word_range.start..offset)
 5109                    .collect::<String>(),
 5110            )
 5111        } else {
 5112            None
 5113        }
 5114    }
 5115
 5116    pub fn toggle_inline_values(
 5117        &mut self,
 5118        _: &ToggleInlineValues,
 5119        _: &mut Window,
 5120        cx: &mut Context<Self>,
 5121    ) {
 5122        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5123
 5124        self.refresh_inline_values(cx);
 5125    }
 5126
 5127    pub fn toggle_inlay_hints(
 5128        &mut self,
 5129        _: &ToggleInlayHints,
 5130        _: &mut Window,
 5131        cx: &mut Context<Self>,
 5132    ) {
 5133        self.refresh_inlay_hints(
 5134            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5135            cx,
 5136        );
 5137    }
 5138
 5139    pub fn inlay_hints_enabled(&self) -> bool {
 5140        self.inlay_hint_cache.enabled
 5141    }
 5142
 5143    pub fn inline_values_enabled(&self) -> bool {
 5144        self.inline_value_cache.enabled
 5145    }
 5146
 5147    #[cfg(any(test, feature = "test-support"))]
 5148    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5149        self.display_map
 5150            .read(cx)
 5151            .current_inlays()
 5152            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5153            .cloned()
 5154            .collect()
 5155    }
 5156
 5157    #[cfg(any(test, feature = "test-support"))]
 5158    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5159        self.display_map
 5160            .read(cx)
 5161            .current_inlays()
 5162            .cloned()
 5163            .collect()
 5164    }
 5165
 5166    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5167        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5168            return;
 5169        }
 5170
 5171        let reason_description = reason.description();
 5172        let ignore_debounce = matches!(
 5173            reason,
 5174            InlayHintRefreshReason::SettingsChange(_)
 5175                | InlayHintRefreshReason::Toggle(_)
 5176                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5177                | InlayHintRefreshReason::ModifiersChanged(_)
 5178        );
 5179        let (invalidate_cache, required_languages) = match reason {
 5180            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5181                match self.inlay_hint_cache.modifiers_override(enabled) {
 5182                    Some(enabled) => {
 5183                        if enabled {
 5184                            (InvalidationStrategy::RefreshRequested, None)
 5185                        } else {
 5186                            self.splice_inlays(
 5187                                &self
 5188                                    .visible_inlay_hints(cx)
 5189                                    .iter()
 5190                                    .map(|inlay| inlay.id)
 5191                                    .collect::<Vec<InlayId>>(),
 5192                                Vec::new(),
 5193                                cx,
 5194                            );
 5195                            return;
 5196                        }
 5197                    }
 5198                    None => return,
 5199                }
 5200            }
 5201            InlayHintRefreshReason::Toggle(enabled) => {
 5202                if self.inlay_hint_cache.toggle(enabled) {
 5203                    if enabled {
 5204                        (InvalidationStrategy::RefreshRequested, None)
 5205                    } else {
 5206                        self.splice_inlays(
 5207                            &self
 5208                                .visible_inlay_hints(cx)
 5209                                .iter()
 5210                                .map(|inlay| inlay.id)
 5211                                .collect::<Vec<InlayId>>(),
 5212                            Vec::new(),
 5213                            cx,
 5214                        );
 5215                        return;
 5216                    }
 5217                } else {
 5218                    return;
 5219                }
 5220            }
 5221            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5222                match self.inlay_hint_cache.update_settings(
 5223                    &self.buffer,
 5224                    new_settings,
 5225                    self.visible_inlay_hints(cx),
 5226                    cx,
 5227                ) {
 5228                    ControlFlow::Break(Some(InlaySplice {
 5229                        to_remove,
 5230                        to_insert,
 5231                    })) => {
 5232                        self.splice_inlays(&to_remove, to_insert, cx);
 5233                        return;
 5234                    }
 5235                    ControlFlow::Break(None) => return,
 5236                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5237                }
 5238            }
 5239            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5240                if let Some(InlaySplice {
 5241                    to_remove,
 5242                    to_insert,
 5243                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5244                {
 5245                    self.splice_inlays(&to_remove, to_insert, cx);
 5246                }
 5247                self.display_map.update(cx, |display_map, _| {
 5248                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5249                });
 5250                return;
 5251            }
 5252            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5253            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5254                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5255            }
 5256            InlayHintRefreshReason::RefreshRequested => {
 5257                (InvalidationStrategy::RefreshRequested, None)
 5258            }
 5259        };
 5260
 5261        if let Some(InlaySplice {
 5262            to_remove,
 5263            to_insert,
 5264        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5265            reason_description,
 5266            self.visible_excerpts(required_languages.as_ref(), cx),
 5267            invalidate_cache,
 5268            ignore_debounce,
 5269            cx,
 5270        ) {
 5271            self.splice_inlays(&to_remove, to_insert, cx);
 5272        }
 5273    }
 5274
 5275    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5276        self.display_map
 5277            .read(cx)
 5278            .current_inlays()
 5279            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5280            .cloned()
 5281            .collect()
 5282    }
 5283
 5284    pub fn visible_excerpts(
 5285        &self,
 5286        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5287        cx: &mut Context<Editor>,
 5288    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5289        let Some(project) = self.project() else {
 5290            return HashMap::default();
 5291        };
 5292        let project = project.read(cx);
 5293        let multi_buffer = self.buffer().read(cx);
 5294        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5295        let multi_buffer_visible_start = self
 5296            .scroll_manager
 5297            .anchor()
 5298            .anchor
 5299            .to_point(&multi_buffer_snapshot);
 5300        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5301            multi_buffer_visible_start
 5302                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5303            Bias::Left,
 5304        );
 5305        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5306        multi_buffer_snapshot
 5307            .range_to_buffer_ranges(multi_buffer_visible_range)
 5308            .into_iter()
 5309            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5310            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5311                let buffer_file = project::File::from_dyn(buffer.file())?;
 5312                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5313                let worktree_entry = buffer_worktree
 5314                    .read(cx)
 5315                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5316                if worktree_entry.is_ignored {
 5317                    return None;
 5318                }
 5319
 5320                let language = buffer.language()?;
 5321                if let Some(restrict_to_languages) = restrict_to_languages
 5322                    && !restrict_to_languages.contains(language)
 5323                {
 5324                    return None;
 5325                }
 5326                Some((
 5327                    excerpt_id,
 5328                    (
 5329                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5330                        buffer.version().clone(),
 5331                        excerpt_visible_range,
 5332                    ),
 5333                ))
 5334            })
 5335            .collect()
 5336    }
 5337
 5338    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5339        TextLayoutDetails {
 5340            text_system: window.text_system().clone(),
 5341            editor_style: self.style.clone().unwrap(),
 5342            rem_size: window.rem_size(),
 5343            scroll_anchor: self.scroll_manager.anchor(),
 5344            visible_rows: self.visible_line_count(),
 5345            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5346        }
 5347    }
 5348
 5349    pub fn splice_inlays(
 5350        &self,
 5351        to_remove: &[InlayId],
 5352        to_insert: Vec<Inlay>,
 5353        cx: &mut Context<Self>,
 5354    ) {
 5355        self.display_map.update(cx, |display_map, cx| {
 5356            display_map.splice_inlays(to_remove, to_insert, cx)
 5357        });
 5358        cx.notify();
 5359    }
 5360
 5361    fn trigger_on_type_formatting(
 5362        &self,
 5363        input: String,
 5364        window: &mut Window,
 5365        cx: &mut Context<Self>,
 5366    ) -> Option<Task<Result<()>>> {
 5367        if input.len() != 1 {
 5368            return None;
 5369        }
 5370
 5371        let project = self.project()?;
 5372        let position = self.selections.newest_anchor().head();
 5373        let (buffer, buffer_position) = self
 5374            .buffer
 5375            .read(cx)
 5376            .text_anchor_for_position(position, cx)?;
 5377
 5378        let settings = language_settings::language_settings(
 5379            buffer
 5380                .read(cx)
 5381                .language_at(buffer_position)
 5382                .map(|l| l.name()),
 5383            buffer.read(cx).file(),
 5384            cx,
 5385        );
 5386        if !settings.use_on_type_format {
 5387            return None;
 5388        }
 5389
 5390        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5391        // hence we do LSP request & edit on host side only — add formats to host's history.
 5392        let push_to_lsp_host_history = true;
 5393        // If this is not the host, append its history with new edits.
 5394        let push_to_client_history = project.read(cx).is_via_collab();
 5395
 5396        let on_type_formatting = project.update(cx, |project, cx| {
 5397            project.on_type_format(
 5398                buffer.clone(),
 5399                buffer_position,
 5400                input,
 5401                push_to_lsp_host_history,
 5402                cx,
 5403            )
 5404        });
 5405        Some(cx.spawn_in(window, async move |editor, cx| {
 5406            if let Some(transaction) = on_type_formatting.await? {
 5407                if push_to_client_history {
 5408                    buffer
 5409                        .update(cx, |buffer, _| {
 5410                            buffer.push_transaction(transaction, Instant::now());
 5411                            buffer.finalize_last_transaction();
 5412                        })
 5413                        .ok();
 5414                }
 5415                editor.update(cx, |editor, cx| {
 5416                    editor.refresh_document_highlights(cx);
 5417                })?;
 5418            }
 5419            Ok(())
 5420        }))
 5421    }
 5422
 5423    pub fn show_word_completions(
 5424        &mut self,
 5425        _: &ShowWordCompletions,
 5426        window: &mut Window,
 5427        cx: &mut Context<Self>,
 5428    ) {
 5429        self.open_or_update_completions_menu(
 5430            Some(CompletionsMenuSource::Words {
 5431                ignore_threshold: true,
 5432            }),
 5433            None,
 5434            window,
 5435            cx,
 5436        );
 5437    }
 5438
 5439    pub fn show_completions(
 5440        &mut self,
 5441        options: &ShowCompletions,
 5442        window: &mut Window,
 5443        cx: &mut Context<Self>,
 5444    ) {
 5445        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5446    }
 5447
 5448    fn open_or_update_completions_menu(
 5449        &mut self,
 5450        requested_source: Option<CompletionsMenuSource>,
 5451        trigger: Option<&str>,
 5452        window: &mut Window,
 5453        cx: &mut Context<Self>,
 5454    ) {
 5455        if self.pending_rename.is_some() {
 5456            return;
 5457        }
 5458
 5459        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5460
 5461        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5462        // inserted and selected. To handle that case, the start of the selection is used so that
 5463        // the menu starts with all choices.
 5464        let position = self
 5465            .selections
 5466            .newest_anchor()
 5467            .start
 5468            .bias_right(&multibuffer_snapshot);
 5469        if position.diff_base_anchor.is_some() {
 5470            return;
 5471        }
 5472        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5473        let Some(buffer) = buffer_position
 5474            .buffer_id
 5475            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5476        else {
 5477            return;
 5478        };
 5479        let buffer_snapshot = buffer.read(cx).snapshot();
 5480
 5481        let query: Option<Arc<String>> =
 5482            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5483                .map(|query| query.into());
 5484
 5485        drop(multibuffer_snapshot);
 5486
 5487        // Hide the current completions menu when query is empty. Without this, cached
 5488        // completions from before the trigger char may be reused (#32774).
 5489        if query.is_none() {
 5490            let menu_is_open = matches!(
 5491                self.context_menu.borrow().as_ref(),
 5492                Some(CodeContextMenu::Completions(_))
 5493            );
 5494            if menu_is_open {
 5495                self.hide_context_menu(window, cx);
 5496            }
 5497        }
 5498
 5499        let mut ignore_word_threshold = false;
 5500        let provider = match requested_source {
 5501            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5502            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5503                ignore_word_threshold = ignore_threshold;
 5504                None
 5505            }
 5506            Some(CompletionsMenuSource::SnippetChoices) => {
 5507                log::error!("bug: SnippetChoices requested_source is not handled");
 5508                None
 5509            }
 5510        };
 5511
 5512        let sort_completions = provider
 5513            .as_ref()
 5514            .is_some_and(|provider| provider.sort_completions());
 5515
 5516        let filter_completions = provider
 5517            .as_ref()
 5518            .is_none_or(|provider| provider.filter_completions());
 5519
 5520        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5521            if filter_completions {
 5522                menu.filter(query.clone(), provider.clone(), window, cx);
 5523            }
 5524            // When `is_incomplete` is false, no need to re-query completions when the current query
 5525            // is a suffix of the initial query.
 5526            if !menu.is_incomplete {
 5527                // If the new query is a suffix of the old query (typing more characters) and
 5528                // the previous result was complete, the existing completions can be filtered.
 5529                //
 5530                // Note that this is always true for snippet completions.
 5531                let query_matches = match (&menu.initial_query, &query) {
 5532                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5533                    (None, _) => true,
 5534                    _ => false,
 5535                };
 5536                if query_matches {
 5537                    let position_matches = if menu.initial_position == position {
 5538                        true
 5539                    } else {
 5540                        let snapshot = self.buffer.read(cx).read(cx);
 5541                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5542                    };
 5543                    if position_matches {
 5544                        return;
 5545                    }
 5546                }
 5547            }
 5548        };
 5549
 5550        let trigger_kind = match trigger {
 5551            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5552                CompletionTriggerKind::TRIGGER_CHARACTER
 5553            }
 5554            _ => CompletionTriggerKind::INVOKED,
 5555        };
 5556        let completion_context = CompletionContext {
 5557            trigger_character: trigger.and_then(|trigger| {
 5558                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5559                    Some(String::from(trigger))
 5560                } else {
 5561                    None
 5562                }
 5563            }),
 5564            trigger_kind,
 5565        };
 5566
 5567        let Anchor {
 5568            excerpt_id: buffer_excerpt_id,
 5569            text_anchor: buffer_position,
 5570            ..
 5571        } = buffer_position;
 5572
 5573        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5574            buffer_snapshot.surrounding_word(buffer_position, false)
 5575        {
 5576            let word_to_exclude = buffer_snapshot
 5577                .text_for_range(word_range.clone())
 5578                .collect::<String>();
 5579            (
 5580                buffer_snapshot.anchor_before(word_range.start)
 5581                    ..buffer_snapshot.anchor_after(buffer_position),
 5582                Some(word_to_exclude),
 5583            )
 5584        } else {
 5585            (buffer_position..buffer_position, None)
 5586        };
 5587
 5588        let language = buffer_snapshot
 5589            .language_at(buffer_position)
 5590            .map(|language| language.name());
 5591
 5592        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5593            .completions
 5594            .clone();
 5595
 5596        let show_completion_documentation = buffer_snapshot
 5597            .settings_at(buffer_position, cx)
 5598            .show_completion_documentation;
 5599
 5600        // The document can be large, so stay in reasonable bounds when searching for words,
 5601        // otherwise completion pop-up might be slow to appear.
 5602        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5603        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5604        let min_word_search = buffer_snapshot.clip_point(
 5605            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5606            Bias::Left,
 5607        );
 5608        let max_word_search = buffer_snapshot.clip_point(
 5609            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5610            Bias::Right,
 5611        );
 5612        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5613            ..buffer_snapshot.point_to_offset(max_word_search);
 5614
 5615        let skip_digits = query
 5616            .as_ref()
 5617            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5618
 5619        let omit_word_completions = !self.word_completions_enabled
 5620            || (!ignore_word_threshold
 5621                && match &query {
 5622                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5623                    None => completion_settings.words_min_length != 0,
 5624                });
 5625
 5626        let (mut words, provider_responses) = match &provider {
 5627            Some(provider) => {
 5628                let provider_responses = provider.completions(
 5629                    buffer_excerpt_id,
 5630                    &buffer,
 5631                    buffer_position,
 5632                    completion_context,
 5633                    window,
 5634                    cx,
 5635                );
 5636
 5637                let words = match (omit_word_completions, completion_settings.words) {
 5638                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5639                        Task::ready(BTreeMap::default())
 5640                    }
 5641                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5642                        .background_spawn(async move {
 5643                            buffer_snapshot.words_in_range(WordsQuery {
 5644                                fuzzy_contents: None,
 5645                                range: word_search_range,
 5646                                skip_digits,
 5647                            })
 5648                        }),
 5649                };
 5650
 5651                (words, provider_responses)
 5652            }
 5653            None => {
 5654                let words = if omit_word_completions {
 5655                    Task::ready(BTreeMap::default())
 5656                } else {
 5657                    cx.background_spawn(async move {
 5658                        buffer_snapshot.words_in_range(WordsQuery {
 5659                            fuzzy_contents: None,
 5660                            range: word_search_range,
 5661                            skip_digits,
 5662                        })
 5663                    })
 5664                };
 5665                (words, Task::ready(Ok(Vec::new())))
 5666            }
 5667        };
 5668
 5669        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5670
 5671        let id = post_inc(&mut self.next_completion_id);
 5672        let task = cx.spawn_in(window, async move |editor, cx| {
 5673            let Ok(()) = editor.update(cx, |this, _| {
 5674                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5675            }) else {
 5676                return;
 5677            };
 5678
 5679            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5680            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5681            let mut completions = Vec::new();
 5682            let mut is_incomplete = false;
 5683            let mut display_options: Option<CompletionDisplayOptions> = None;
 5684            if let Some(provider_responses) = provider_responses.await.log_err()
 5685                && !provider_responses.is_empty()
 5686            {
 5687                for response in provider_responses {
 5688                    completions.extend(response.completions);
 5689                    is_incomplete = is_incomplete || response.is_incomplete;
 5690                    match display_options.as_mut() {
 5691                        None => {
 5692                            display_options = Some(response.display_options);
 5693                        }
 5694                        Some(options) => options.merge(&response.display_options),
 5695                    }
 5696                }
 5697                if completion_settings.words == WordsCompletionMode::Fallback {
 5698                    words = Task::ready(BTreeMap::default());
 5699                }
 5700            }
 5701            let display_options = display_options.unwrap_or_default();
 5702
 5703            let mut words = words.await;
 5704            if let Some(word_to_exclude) = &word_to_exclude {
 5705                words.remove(word_to_exclude);
 5706            }
 5707            for lsp_completion in &completions {
 5708                words.remove(&lsp_completion.new_text);
 5709            }
 5710            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5711                replace_range: word_replace_range.clone(),
 5712                new_text: word.clone(),
 5713                label: CodeLabel::plain(word, None),
 5714                icon_path: None,
 5715                documentation: None,
 5716                source: CompletionSource::BufferWord {
 5717                    word_range,
 5718                    resolved: false,
 5719                },
 5720                insert_text_mode: Some(InsertTextMode::AS_IS),
 5721                confirm: None,
 5722            }));
 5723
 5724            let menu = if completions.is_empty() {
 5725                None
 5726            } else {
 5727                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5728                    let languages = editor
 5729                        .workspace
 5730                        .as_ref()
 5731                        .and_then(|(workspace, _)| workspace.upgrade())
 5732                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5733                    let menu = CompletionsMenu::new(
 5734                        id,
 5735                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5736                        sort_completions,
 5737                        show_completion_documentation,
 5738                        position,
 5739                        query.clone(),
 5740                        is_incomplete,
 5741                        buffer.clone(),
 5742                        completions.into(),
 5743                        display_options,
 5744                        snippet_sort_order,
 5745                        languages,
 5746                        language,
 5747                        cx,
 5748                    );
 5749
 5750                    let query = if filter_completions { query } else { None };
 5751                    let matches_task = if let Some(query) = query {
 5752                        menu.do_async_filtering(query, cx)
 5753                    } else {
 5754                        Task::ready(menu.unfiltered_matches())
 5755                    };
 5756                    (menu, matches_task)
 5757                }) else {
 5758                    return;
 5759                };
 5760
 5761                let matches = matches_task.await;
 5762
 5763                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5764                    // Newer menu already set, so exit.
 5765                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5766                        editor.context_menu.borrow().as_ref()
 5767                        && prev_menu.id > id
 5768                    {
 5769                        return;
 5770                    };
 5771
 5772                    // Only valid to take prev_menu because it the new menu is immediately set
 5773                    // below, or the menu is hidden.
 5774                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5775                        editor.context_menu.borrow_mut().take()
 5776                    {
 5777                        let position_matches =
 5778                            if prev_menu.initial_position == menu.initial_position {
 5779                                true
 5780                            } else {
 5781                                let snapshot = editor.buffer.read(cx).read(cx);
 5782                                prev_menu.initial_position.to_offset(&snapshot)
 5783                                    == menu.initial_position.to_offset(&snapshot)
 5784                            };
 5785                        if position_matches {
 5786                            // Preserve markdown cache before `set_filter_results` because it will
 5787                            // try to populate the documentation cache.
 5788                            menu.preserve_markdown_cache(prev_menu);
 5789                        }
 5790                    };
 5791
 5792                    menu.set_filter_results(matches, provider, window, cx);
 5793                }) else {
 5794                    return;
 5795                };
 5796
 5797                menu.visible().then_some(menu)
 5798            };
 5799
 5800            editor
 5801                .update_in(cx, |editor, window, cx| {
 5802                    if editor.focus_handle.is_focused(window)
 5803                        && let Some(menu) = menu
 5804                    {
 5805                        *editor.context_menu.borrow_mut() =
 5806                            Some(CodeContextMenu::Completions(menu));
 5807
 5808                        crate::hover_popover::hide_hover(editor, cx);
 5809                        if editor.show_edit_predictions_in_menu() {
 5810                            editor.update_visible_edit_prediction(window, cx);
 5811                        } else {
 5812                            editor.discard_edit_prediction(false, cx);
 5813                        }
 5814
 5815                        cx.notify();
 5816                        return;
 5817                    }
 5818
 5819                    if editor.completion_tasks.len() <= 1 {
 5820                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5821                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5822                        // If it was already hidden and we don't show edit predictions in the menu,
 5823                        // we should also show the edit prediction when available.
 5824                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5825                            editor.update_visible_edit_prediction(window, cx);
 5826                        }
 5827                    }
 5828                })
 5829                .ok();
 5830        });
 5831
 5832        self.completion_tasks.push((id, task));
 5833    }
 5834
 5835    #[cfg(feature = "test-support")]
 5836    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5837        let menu = self.context_menu.borrow();
 5838        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5839            let completions = menu.completions.borrow();
 5840            Some(completions.to_vec())
 5841        } else {
 5842            None
 5843        }
 5844    }
 5845
 5846    pub fn with_completions_menu_matching_id<R>(
 5847        &self,
 5848        id: CompletionId,
 5849        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5850    ) -> R {
 5851        let mut context_menu = self.context_menu.borrow_mut();
 5852        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5853            return f(None);
 5854        };
 5855        if completions_menu.id != id {
 5856            return f(None);
 5857        }
 5858        f(Some(completions_menu))
 5859    }
 5860
 5861    pub fn confirm_completion(
 5862        &mut self,
 5863        action: &ConfirmCompletion,
 5864        window: &mut Window,
 5865        cx: &mut Context<Self>,
 5866    ) -> Option<Task<Result<()>>> {
 5867        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5868        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5869    }
 5870
 5871    pub fn confirm_completion_insert(
 5872        &mut self,
 5873        _: &ConfirmCompletionInsert,
 5874        window: &mut Window,
 5875        cx: &mut Context<Self>,
 5876    ) -> Option<Task<Result<()>>> {
 5877        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5878        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5879    }
 5880
 5881    pub fn confirm_completion_replace(
 5882        &mut self,
 5883        _: &ConfirmCompletionReplace,
 5884        window: &mut Window,
 5885        cx: &mut Context<Self>,
 5886    ) -> Option<Task<Result<()>>> {
 5887        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5888        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5889    }
 5890
 5891    pub fn compose_completion(
 5892        &mut self,
 5893        action: &ComposeCompletion,
 5894        window: &mut Window,
 5895        cx: &mut Context<Self>,
 5896    ) -> Option<Task<Result<()>>> {
 5897        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5898        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5899    }
 5900
 5901    fn do_completion(
 5902        &mut self,
 5903        item_ix: Option<usize>,
 5904        intent: CompletionIntent,
 5905        window: &mut Window,
 5906        cx: &mut Context<Editor>,
 5907    ) -> Option<Task<Result<()>>> {
 5908        use language::ToOffset as _;
 5909
 5910        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5911        else {
 5912            return None;
 5913        };
 5914
 5915        let candidate_id = {
 5916            let entries = completions_menu.entries.borrow();
 5917            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5918            if self.show_edit_predictions_in_menu() {
 5919                self.discard_edit_prediction(true, cx);
 5920            }
 5921            mat.candidate_id
 5922        };
 5923
 5924        let completion = completions_menu
 5925            .completions
 5926            .borrow()
 5927            .get(candidate_id)?
 5928            .clone();
 5929        cx.stop_propagation();
 5930
 5931        let buffer_handle = completions_menu.buffer.clone();
 5932
 5933        let CompletionEdit {
 5934            new_text,
 5935            snippet,
 5936            replace_range,
 5937        } = process_completion_for_edit(
 5938            &completion,
 5939            intent,
 5940            &buffer_handle,
 5941            &completions_menu.initial_position.text_anchor,
 5942            cx,
 5943        );
 5944
 5945        let buffer = buffer_handle.read(cx);
 5946        let snapshot = self.buffer.read(cx).snapshot(cx);
 5947        let newest_anchor = self.selections.newest_anchor();
 5948        let replace_range_multibuffer = {
 5949            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5950            let multibuffer_anchor = snapshot
 5951                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5952                .unwrap()
 5953                ..snapshot
 5954                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5955                    .unwrap();
 5956            multibuffer_anchor.start.to_offset(&snapshot)
 5957                ..multibuffer_anchor.end.to_offset(&snapshot)
 5958        };
 5959        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5960            return None;
 5961        }
 5962
 5963        let old_text = buffer
 5964            .text_for_range(replace_range.clone())
 5965            .collect::<String>();
 5966        let lookbehind = newest_anchor
 5967            .start
 5968            .text_anchor
 5969            .to_offset(buffer)
 5970            .saturating_sub(replace_range.start);
 5971        let lookahead = replace_range
 5972            .end
 5973            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5974        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5975        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5976
 5977        let selections = self.selections.all::<usize>(cx);
 5978        let mut ranges = Vec::new();
 5979        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5980
 5981        for selection in &selections {
 5982            let range = if selection.id == newest_anchor.id {
 5983                replace_range_multibuffer.clone()
 5984            } else {
 5985                let mut range = selection.range();
 5986
 5987                // if prefix is present, don't duplicate it
 5988                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5989                    range.start = range.start.saturating_sub(lookbehind);
 5990
 5991                    // if suffix is also present, mimic the newest cursor and replace it
 5992                    if selection.id != newest_anchor.id
 5993                        && snapshot.contains_str_at(range.end, suffix)
 5994                    {
 5995                        range.end += lookahead;
 5996                    }
 5997                }
 5998                range
 5999            };
 6000
 6001            ranges.push(range.clone());
 6002
 6003            if !self.linked_edit_ranges.is_empty() {
 6004                let start_anchor = snapshot.anchor_before(range.start);
 6005                let end_anchor = snapshot.anchor_after(range.end);
 6006                if let Some(ranges) = self
 6007                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6008                {
 6009                    for (buffer, edits) in ranges {
 6010                        linked_edits
 6011                            .entry(buffer.clone())
 6012                            .or_default()
 6013                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6014                    }
 6015                }
 6016            }
 6017        }
 6018
 6019        let common_prefix_len = old_text
 6020            .chars()
 6021            .zip(new_text.chars())
 6022            .take_while(|(a, b)| a == b)
 6023            .map(|(a, _)| a.len_utf8())
 6024            .sum::<usize>();
 6025
 6026        cx.emit(EditorEvent::InputHandled {
 6027            utf16_range_to_replace: None,
 6028            text: new_text[common_prefix_len..].into(),
 6029        });
 6030
 6031        self.transact(window, cx, |editor, window, cx| {
 6032            if let Some(mut snippet) = snippet {
 6033                snippet.text = new_text.to_string();
 6034                editor
 6035                    .insert_snippet(&ranges, snippet, window, cx)
 6036                    .log_err();
 6037            } else {
 6038                editor.buffer.update(cx, |multi_buffer, cx| {
 6039                    let auto_indent = match completion.insert_text_mode {
 6040                        Some(InsertTextMode::AS_IS) => None,
 6041                        _ => editor.autoindent_mode.clone(),
 6042                    };
 6043                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6044                    multi_buffer.edit(edits, auto_indent, cx);
 6045                });
 6046            }
 6047            for (buffer, edits) in linked_edits {
 6048                buffer.update(cx, |buffer, cx| {
 6049                    let snapshot = buffer.snapshot();
 6050                    let edits = edits
 6051                        .into_iter()
 6052                        .map(|(range, text)| {
 6053                            use text::ToPoint as TP;
 6054                            let end_point = TP::to_point(&range.end, &snapshot);
 6055                            let start_point = TP::to_point(&range.start, &snapshot);
 6056                            (start_point..end_point, text)
 6057                        })
 6058                        .sorted_by_key(|(range, _)| range.start);
 6059                    buffer.edit(edits, None, cx);
 6060                })
 6061            }
 6062
 6063            editor.refresh_edit_prediction(true, false, window, cx);
 6064        });
 6065        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6066
 6067        let show_new_completions_on_confirm = completion
 6068            .confirm
 6069            .as_ref()
 6070            .is_some_and(|confirm| confirm(intent, window, cx));
 6071        if show_new_completions_on_confirm {
 6072            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6073        }
 6074
 6075        let provider = self.completion_provider.as_ref()?;
 6076        drop(completion);
 6077        let apply_edits = provider.apply_additional_edits_for_completion(
 6078            buffer_handle,
 6079            completions_menu.completions.clone(),
 6080            candidate_id,
 6081            true,
 6082            cx,
 6083        );
 6084
 6085        let editor_settings = EditorSettings::get_global(cx);
 6086        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6087            // After the code completion is finished, users often want to know what signatures are needed.
 6088            // so we should automatically call signature_help
 6089            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6090        }
 6091
 6092        Some(cx.foreground_executor().spawn(async move {
 6093            apply_edits.await?;
 6094            Ok(())
 6095        }))
 6096    }
 6097
 6098    pub fn toggle_code_actions(
 6099        &mut self,
 6100        action: &ToggleCodeActions,
 6101        window: &mut Window,
 6102        cx: &mut Context<Self>,
 6103    ) {
 6104        let quick_launch = action.quick_launch;
 6105        let mut context_menu = self.context_menu.borrow_mut();
 6106        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6107            if code_actions.deployed_from == action.deployed_from {
 6108                // Toggle if we're selecting the same one
 6109                *context_menu = None;
 6110                cx.notify();
 6111                return;
 6112            } else {
 6113                // Otherwise, clear it and start a new one
 6114                *context_menu = None;
 6115                cx.notify();
 6116            }
 6117        }
 6118        drop(context_menu);
 6119        let snapshot = self.snapshot(window, cx);
 6120        let deployed_from = action.deployed_from.clone();
 6121        let action = action.clone();
 6122        self.completion_tasks.clear();
 6123        self.discard_edit_prediction(false, cx);
 6124
 6125        let multibuffer_point = match &action.deployed_from {
 6126            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6127                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6128            }
 6129            _ => self.selections.newest::<Point>(cx).head(),
 6130        };
 6131        let Some((buffer, buffer_row)) = snapshot
 6132            .buffer_snapshot
 6133            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6134            .and_then(|(buffer_snapshot, range)| {
 6135                self.buffer()
 6136                    .read(cx)
 6137                    .buffer(buffer_snapshot.remote_id())
 6138                    .map(|buffer| (buffer, range.start.row))
 6139            })
 6140        else {
 6141            return;
 6142        };
 6143        let buffer_id = buffer.read(cx).remote_id();
 6144        let tasks = self
 6145            .tasks
 6146            .get(&(buffer_id, buffer_row))
 6147            .map(|t| Arc::new(t.to_owned()));
 6148
 6149        if !self.focus_handle.is_focused(window) {
 6150            return;
 6151        }
 6152        let project = self.project.clone();
 6153
 6154        let code_actions_task = match deployed_from {
 6155            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6156            _ => self.code_actions(buffer_row, window, cx),
 6157        };
 6158
 6159        let runnable_task = match deployed_from {
 6160            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6161            _ => {
 6162                let mut task_context_task = Task::ready(None);
 6163                if let Some(tasks) = &tasks
 6164                    && let Some(project) = project
 6165                {
 6166                    task_context_task =
 6167                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6168                }
 6169
 6170                cx.spawn_in(window, {
 6171                    let buffer = buffer.clone();
 6172                    async move |editor, cx| {
 6173                        let task_context = task_context_task.await;
 6174
 6175                        let resolved_tasks =
 6176                            tasks
 6177                                .zip(task_context.clone())
 6178                                .map(|(tasks, task_context)| ResolvedTasks {
 6179                                    templates: tasks.resolve(&task_context).collect(),
 6180                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6181                                        multibuffer_point.row,
 6182                                        tasks.column,
 6183                                    )),
 6184                                });
 6185                        let debug_scenarios = editor
 6186                            .update(cx, |editor, cx| {
 6187                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6188                            })?
 6189                            .await;
 6190                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6191                    }
 6192                })
 6193            }
 6194        };
 6195
 6196        cx.spawn_in(window, async move |editor, cx| {
 6197            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6198            let code_actions = code_actions_task.await;
 6199            let spawn_straight_away = quick_launch
 6200                && resolved_tasks
 6201                    .as_ref()
 6202                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6203                && code_actions
 6204                    .as_ref()
 6205                    .is_none_or(|actions| actions.is_empty())
 6206                && debug_scenarios.is_empty();
 6207
 6208            editor.update_in(cx, |editor, window, cx| {
 6209                crate::hover_popover::hide_hover(editor, cx);
 6210                let actions = CodeActionContents::new(
 6211                    resolved_tasks,
 6212                    code_actions,
 6213                    debug_scenarios,
 6214                    task_context.unwrap_or_default(),
 6215                );
 6216
 6217                // Don't show the menu if there are no actions available
 6218                if actions.is_empty() {
 6219                    cx.notify();
 6220                    return Task::ready(Ok(()));
 6221                }
 6222
 6223                *editor.context_menu.borrow_mut() =
 6224                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6225                        buffer,
 6226                        actions,
 6227                        selected_item: Default::default(),
 6228                        scroll_handle: UniformListScrollHandle::default(),
 6229                        deployed_from,
 6230                    }));
 6231                cx.notify();
 6232                if spawn_straight_away
 6233                    && let Some(task) = editor.confirm_code_action(
 6234                        &ConfirmCodeAction { item_ix: Some(0) },
 6235                        window,
 6236                        cx,
 6237                    )
 6238                {
 6239                    return task;
 6240                }
 6241
 6242                Task::ready(Ok(()))
 6243            })
 6244        })
 6245        .detach_and_log_err(cx);
 6246    }
 6247
 6248    fn debug_scenarios(
 6249        &mut self,
 6250        resolved_tasks: &Option<ResolvedTasks>,
 6251        buffer: &Entity<Buffer>,
 6252        cx: &mut App,
 6253    ) -> Task<Vec<task::DebugScenario>> {
 6254        maybe!({
 6255            let project = self.project()?;
 6256            let dap_store = project.read(cx).dap_store();
 6257            let mut scenarios = vec![];
 6258            let resolved_tasks = resolved_tasks.as_ref()?;
 6259            let buffer = buffer.read(cx);
 6260            let language = buffer.language()?;
 6261            let file = buffer.file();
 6262            let debug_adapter = language_settings(language.name().into(), file, cx)
 6263                .debuggers
 6264                .first()
 6265                .map(SharedString::from)
 6266                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6267
 6268            dap_store.update(cx, |dap_store, cx| {
 6269                for (_, task) in &resolved_tasks.templates {
 6270                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6271                        task.original_task().clone(),
 6272                        debug_adapter.clone().into(),
 6273                        task.display_label().to_owned().into(),
 6274                        cx,
 6275                    );
 6276                    scenarios.push(maybe_scenario);
 6277                }
 6278            });
 6279            Some(cx.background_spawn(async move {
 6280                futures::future::join_all(scenarios)
 6281                    .await
 6282                    .into_iter()
 6283                    .flatten()
 6284                    .collect::<Vec<_>>()
 6285            }))
 6286        })
 6287        .unwrap_or_else(|| Task::ready(vec![]))
 6288    }
 6289
 6290    fn code_actions(
 6291        &mut self,
 6292        buffer_row: u32,
 6293        window: &mut Window,
 6294        cx: &mut Context<Self>,
 6295    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6296        let mut task = self.code_actions_task.take();
 6297        cx.spawn_in(window, async move |editor, cx| {
 6298            while let Some(prev_task) = task {
 6299                prev_task.await.log_err();
 6300                task = editor
 6301                    .update(cx, |this, _| this.code_actions_task.take())
 6302                    .ok()?;
 6303            }
 6304
 6305            editor
 6306                .update(cx, |editor, cx| {
 6307                    editor
 6308                        .available_code_actions
 6309                        .clone()
 6310                        .and_then(|(location, code_actions)| {
 6311                            let snapshot = location.buffer.read(cx).snapshot();
 6312                            let point_range = location.range.to_point(&snapshot);
 6313                            let point_range = point_range.start.row..=point_range.end.row;
 6314                            if point_range.contains(&buffer_row) {
 6315                                Some(code_actions)
 6316                            } else {
 6317                                None
 6318                            }
 6319                        })
 6320                })
 6321                .ok()
 6322                .flatten()
 6323        })
 6324    }
 6325
 6326    pub fn confirm_code_action(
 6327        &mut self,
 6328        action: &ConfirmCodeAction,
 6329        window: &mut Window,
 6330        cx: &mut Context<Self>,
 6331    ) -> Option<Task<Result<()>>> {
 6332        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6333
 6334        let actions_menu =
 6335            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6336                menu
 6337            } else {
 6338                return None;
 6339            };
 6340
 6341        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6342        let action = actions_menu.actions.get(action_ix)?;
 6343        let title = action.label();
 6344        let buffer = actions_menu.buffer;
 6345        let workspace = self.workspace()?;
 6346
 6347        match action {
 6348            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6349                workspace.update(cx, |workspace, cx| {
 6350                    workspace.schedule_resolved_task(
 6351                        task_source_kind,
 6352                        resolved_task,
 6353                        false,
 6354                        window,
 6355                        cx,
 6356                    );
 6357
 6358                    Some(Task::ready(Ok(())))
 6359                })
 6360            }
 6361            CodeActionsItem::CodeAction {
 6362                excerpt_id,
 6363                action,
 6364                provider,
 6365            } => {
 6366                let apply_code_action =
 6367                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6368                let workspace = workspace.downgrade();
 6369                Some(cx.spawn_in(window, async move |editor, cx| {
 6370                    let project_transaction = apply_code_action.await?;
 6371                    Self::open_project_transaction(
 6372                        &editor,
 6373                        workspace,
 6374                        project_transaction,
 6375                        title,
 6376                        cx,
 6377                    )
 6378                    .await
 6379                }))
 6380            }
 6381            CodeActionsItem::DebugScenario(scenario) => {
 6382                let context = actions_menu.actions.context;
 6383
 6384                workspace.update(cx, |workspace, cx| {
 6385                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6386                    workspace.start_debug_session(
 6387                        scenario,
 6388                        context,
 6389                        Some(buffer),
 6390                        None,
 6391                        window,
 6392                        cx,
 6393                    );
 6394                });
 6395                Some(Task::ready(Ok(())))
 6396            }
 6397        }
 6398    }
 6399
 6400    pub async fn open_project_transaction(
 6401        editor: &WeakEntity<Editor>,
 6402        workspace: WeakEntity<Workspace>,
 6403        transaction: ProjectTransaction,
 6404        title: String,
 6405        cx: &mut AsyncWindowContext,
 6406    ) -> Result<()> {
 6407        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6408        cx.update(|_, cx| {
 6409            entries.sort_unstable_by_key(|(buffer, _)| {
 6410                buffer.read(cx).file().map(|f| f.path().clone())
 6411            });
 6412        })?;
 6413
 6414        // If the project transaction's edits are all contained within this editor, then
 6415        // avoid opening a new editor to display them.
 6416
 6417        if let Some((buffer, transaction)) = entries.first() {
 6418            if entries.len() == 1 {
 6419                let excerpt = editor.update(cx, |editor, cx| {
 6420                    editor
 6421                        .buffer()
 6422                        .read(cx)
 6423                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6424                })?;
 6425                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6426                    && excerpted_buffer == *buffer
 6427                {
 6428                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6429                        let excerpt_range = excerpt_range.to_offset(buffer);
 6430                        buffer
 6431                            .edited_ranges_for_transaction::<usize>(transaction)
 6432                            .all(|range| {
 6433                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6434                            })
 6435                    })?;
 6436
 6437                    if all_edits_within_excerpt {
 6438                        return Ok(());
 6439                    }
 6440                }
 6441            }
 6442        } else {
 6443            return Ok(());
 6444        }
 6445
 6446        let mut ranges_to_highlight = Vec::new();
 6447        let excerpt_buffer = cx.new(|cx| {
 6448            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6449            for (buffer_handle, transaction) in &entries {
 6450                let edited_ranges = buffer_handle
 6451                    .read(cx)
 6452                    .edited_ranges_for_transaction::<Point>(transaction)
 6453                    .collect::<Vec<_>>();
 6454                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6455                    PathKey::for_buffer(buffer_handle, cx),
 6456                    buffer_handle.clone(),
 6457                    edited_ranges,
 6458                    multibuffer_context_lines(cx),
 6459                    cx,
 6460                );
 6461
 6462                ranges_to_highlight.extend(ranges);
 6463            }
 6464            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6465            multibuffer
 6466        })?;
 6467
 6468        workspace.update_in(cx, |workspace, window, cx| {
 6469            let project = workspace.project().clone();
 6470            let editor =
 6471                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6472            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6473            editor.update(cx, |editor, cx| {
 6474                editor.highlight_background::<Self>(
 6475                    &ranges_to_highlight,
 6476                    |theme| theme.colors().editor_highlighted_line_background,
 6477                    cx,
 6478                );
 6479            });
 6480        })?;
 6481
 6482        Ok(())
 6483    }
 6484
 6485    pub fn clear_code_action_providers(&mut self) {
 6486        self.code_action_providers.clear();
 6487        self.available_code_actions.take();
 6488    }
 6489
 6490    pub fn add_code_action_provider(
 6491        &mut self,
 6492        provider: Rc<dyn CodeActionProvider>,
 6493        window: &mut Window,
 6494        cx: &mut Context<Self>,
 6495    ) {
 6496        if self
 6497            .code_action_providers
 6498            .iter()
 6499            .any(|existing_provider| existing_provider.id() == provider.id())
 6500        {
 6501            return;
 6502        }
 6503
 6504        self.code_action_providers.push(provider);
 6505        self.refresh_code_actions(window, cx);
 6506    }
 6507
 6508    pub fn remove_code_action_provider(
 6509        &mut self,
 6510        id: Arc<str>,
 6511        window: &mut Window,
 6512        cx: &mut Context<Self>,
 6513    ) {
 6514        self.code_action_providers
 6515            .retain(|provider| provider.id() != id);
 6516        self.refresh_code_actions(window, cx);
 6517    }
 6518
 6519    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6520        !self.code_action_providers.is_empty()
 6521            && EditorSettings::get_global(cx).toolbar.code_actions
 6522    }
 6523
 6524    pub fn has_available_code_actions(&self) -> bool {
 6525        self.available_code_actions
 6526            .as_ref()
 6527            .is_some_and(|(_, actions)| !actions.is_empty())
 6528    }
 6529
 6530    fn render_inline_code_actions(
 6531        &self,
 6532        icon_size: ui::IconSize,
 6533        display_row: DisplayRow,
 6534        is_active: bool,
 6535        cx: &mut Context<Self>,
 6536    ) -> AnyElement {
 6537        let show_tooltip = !self.context_menu_visible();
 6538        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6539            .icon_size(icon_size)
 6540            .shape(ui::IconButtonShape::Square)
 6541            .icon_color(ui::Color::Hidden)
 6542            .toggle_state(is_active)
 6543            .when(show_tooltip, |this| {
 6544                this.tooltip({
 6545                    let focus_handle = self.focus_handle.clone();
 6546                    move |window, cx| {
 6547                        Tooltip::for_action_in(
 6548                            "Toggle Code Actions",
 6549                            &ToggleCodeActions {
 6550                                deployed_from: None,
 6551                                quick_launch: false,
 6552                            },
 6553                            &focus_handle,
 6554                            window,
 6555                            cx,
 6556                        )
 6557                    }
 6558                })
 6559            })
 6560            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6561                window.focus(&editor.focus_handle(cx));
 6562                editor.toggle_code_actions(
 6563                    &crate::actions::ToggleCodeActions {
 6564                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6565                            display_row,
 6566                        )),
 6567                        quick_launch: false,
 6568                    },
 6569                    window,
 6570                    cx,
 6571                );
 6572            }))
 6573            .into_any_element()
 6574    }
 6575
 6576    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6577        &self.context_menu
 6578    }
 6579
 6580    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6581        let newest_selection = self.selections.newest_anchor().clone();
 6582        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6583        let buffer = self.buffer.read(cx);
 6584        if newest_selection.head().diff_base_anchor.is_some() {
 6585            return None;
 6586        }
 6587        let (start_buffer, start) =
 6588            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6589        let (end_buffer, end) =
 6590            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6591        if start_buffer != end_buffer {
 6592            return None;
 6593        }
 6594
 6595        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6596            cx.background_executor()
 6597                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6598                .await;
 6599
 6600            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6601                let providers = this.code_action_providers.clone();
 6602                let tasks = this
 6603                    .code_action_providers
 6604                    .iter()
 6605                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6606                    .collect::<Vec<_>>();
 6607                (providers, tasks)
 6608            })?;
 6609
 6610            let mut actions = Vec::new();
 6611            for (provider, provider_actions) in
 6612                providers.into_iter().zip(future::join_all(tasks).await)
 6613            {
 6614                if let Some(provider_actions) = provider_actions.log_err() {
 6615                    actions.extend(provider_actions.into_iter().map(|action| {
 6616                        AvailableCodeAction {
 6617                            excerpt_id: newest_selection.start.excerpt_id,
 6618                            action,
 6619                            provider: provider.clone(),
 6620                        }
 6621                    }));
 6622                }
 6623            }
 6624
 6625            this.update(cx, |this, cx| {
 6626                this.available_code_actions = if actions.is_empty() {
 6627                    None
 6628                } else {
 6629                    Some((
 6630                        Location {
 6631                            buffer: start_buffer,
 6632                            range: start..end,
 6633                        },
 6634                        actions.into(),
 6635                    ))
 6636                };
 6637                cx.notify();
 6638            })
 6639        }));
 6640        None
 6641    }
 6642
 6643    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6644        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6645            self.show_git_blame_inline = false;
 6646
 6647            self.show_git_blame_inline_delay_task =
 6648                Some(cx.spawn_in(window, async move |this, cx| {
 6649                    cx.background_executor().timer(delay).await;
 6650
 6651                    this.update(cx, |this, cx| {
 6652                        this.show_git_blame_inline = true;
 6653                        cx.notify();
 6654                    })
 6655                    .log_err();
 6656                }));
 6657        }
 6658    }
 6659
 6660    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6661        let snapshot = self.snapshot(window, cx);
 6662        let cursor = self.selections.newest::<Point>(cx).head();
 6663        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6664        else {
 6665            return;
 6666        };
 6667
 6668        let Some(blame) = self.blame.as_ref() else {
 6669            return;
 6670        };
 6671
 6672        let row_info = RowInfo {
 6673            buffer_id: Some(buffer.remote_id()),
 6674            buffer_row: Some(point.row),
 6675            ..Default::default()
 6676        };
 6677        let Some((buffer, blame_entry)) = blame
 6678            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6679            .flatten()
 6680        else {
 6681            return;
 6682        };
 6683
 6684        let anchor = self.selections.newest_anchor().head();
 6685        let position = self.to_pixel_point(anchor, &snapshot, window);
 6686        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6687            self.show_blame_popover(
 6688                buffer,
 6689                &blame_entry,
 6690                position + last_bounds.origin,
 6691                true,
 6692                cx,
 6693            );
 6694        };
 6695    }
 6696
 6697    fn show_blame_popover(
 6698        &mut self,
 6699        buffer: BufferId,
 6700        blame_entry: &BlameEntry,
 6701        position: gpui::Point<Pixels>,
 6702        ignore_timeout: bool,
 6703        cx: &mut Context<Self>,
 6704    ) {
 6705        if let Some(state) = &mut self.inline_blame_popover {
 6706            state.hide_task.take();
 6707        } else {
 6708            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6709            let blame_entry = blame_entry.clone();
 6710            let show_task = cx.spawn(async move |editor, cx| {
 6711                if !ignore_timeout {
 6712                    cx.background_executor()
 6713                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6714                        .await;
 6715                }
 6716                editor
 6717                    .update(cx, |editor, cx| {
 6718                        editor.inline_blame_popover_show_task.take();
 6719                        let Some(blame) = editor.blame.as_ref() else {
 6720                            return;
 6721                        };
 6722                        let blame = blame.read(cx);
 6723                        let details = blame.details_for_entry(buffer, &blame_entry);
 6724                        let markdown = cx.new(|cx| {
 6725                            Markdown::new(
 6726                                details
 6727                                    .as_ref()
 6728                                    .map(|message| message.message.clone())
 6729                                    .unwrap_or_default(),
 6730                                None,
 6731                                None,
 6732                                cx,
 6733                            )
 6734                        });
 6735                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6736                            position,
 6737                            hide_task: None,
 6738                            popover_bounds: None,
 6739                            popover_state: InlineBlamePopoverState {
 6740                                scroll_handle: ScrollHandle::new(),
 6741                                commit_message: details,
 6742                                markdown,
 6743                            },
 6744                            keyboard_grace: ignore_timeout,
 6745                        });
 6746                        cx.notify();
 6747                    })
 6748                    .ok();
 6749            });
 6750            self.inline_blame_popover_show_task = Some(show_task);
 6751        }
 6752    }
 6753
 6754    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6755        self.inline_blame_popover_show_task.take();
 6756        if let Some(state) = &mut self.inline_blame_popover {
 6757            let hide_task = cx.spawn(async move |editor, cx| {
 6758                cx.background_executor()
 6759                    .timer(std::time::Duration::from_millis(100))
 6760                    .await;
 6761                editor
 6762                    .update(cx, |editor, cx| {
 6763                        editor.inline_blame_popover.take();
 6764                        cx.notify();
 6765                    })
 6766                    .ok();
 6767            });
 6768            state.hide_task = Some(hide_task);
 6769        }
 6770    }
 6771
 6772    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6773        if self.pending_rename.is_some() {
 6774            return None;
 6775        }
 6776
 6777        let provider = self.semantics_provider.clone()?;
 6778        let buffer = self.buffer.read(cx);
 6779        let newest_selection = self.selections.newest_anchor().clone();
 6780        let cursor_position = newest_selection.head();
 6781        let (cursor_buffer, cursor_buffer_position) =
 6782            buffer.text_anchor_for_position(cursor_position, cx)?;
 6783        let (tail_buffer, tail_buffer_position) =
 6784            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6785        if cursor_buffer != tail_buffer {
 6786            return None;
 6787        }
 6788
 6789        let snapshot = cursor_buffer.read(cx).snapshot();
 6790        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6791        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6792        if start_word_range != end_word_range {
 6793            self.document_highlights_task.take();
 6794            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6795            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6796            return None;
 6797        }
 6798
 6799        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6800        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6801            cx.background_executor()
 6802                .timer(Duration::from_millis(debounce))
 6803                .await;
 6804
 6805            let highlights = if let Some(highlights) = cx
 6806                .update(|cx| {
 6807                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6808                })
 6809                .ok()
 6810                .flatten()
 6811            {
 6812                highlights.await.log_err()
 6813            } else {
 6814                None
 6815            };
 6816
 6817            if let Some(highlights) = highlights {
 6818                this.update(cx, |this, cx| {
 6819                    if this.pending_rename.is_some() {
 6820                        return;
 6821                    }
 6822
 6823                    let buffer = this.buffer.read(cx);
 6824                    if buffer
 6825                        .text_anchor_for_position(cursor_position, cx)
 6826                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6827                    {
 6828                        return;
 6829                    }
 6830
 6831                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6832                    let mut write_ranges = Vec::new();
 6833                    let mut read_ranges = Vec::new();
 6834                    for highlight in highlights {
 6835                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6836                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6837                        {
 6838                            let start = highlight
 6839                                .range
 6840                                .start
 6841                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6842                            let end = highlight
 6843                                .range
 6844                                .end
 6845                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6846                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6847                                continue;
 6848                            }
 6849
 6850                            let range = Anchor {
 6851                                buffer_id: Some(buffer_id),
 6852                                excerpt_id,
 6853                                text_anchor: start,
 6854                                diff_base_anchor: None,
 6855                            }..Anchor {
 6856                                buffer_id: Some(buffer_id),
 6857                                excerpt_id,
 6858                                text_anchor: end,
 6859                                diff_base_anchor: None,
 6860                            };
 6861                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6862                                write_ranges.push(range);
 6863                            } else {
 6864                                read_ranges.push(range);
 6865                            }
 6866                        }
 6867                    }
 6868
 6869                    this.highlight_background::<DocumentHighlightRead>(
 6870                        &read_ranges,
 6871                        |theme| theme.colors().editor_document_highlight_read_background,
 6872                        cx,
 6873                    );
 6874                    this.highlight_background::<DocumentHighlightWrite>(
 6875                        &write_ranges,
 6876                        |theme| theme.colors().editor_document_highlight_write_background,
 6877                        cx,
 6878                    );
 6879                    cx.notify();
 6880                })
 6881                .log_err();
 6882            }
 6883        }));
 6884        None
 6885    }
 6886
 6887    fn prepare_highlight_query_from_selection(
 6888        &mut self,
 6889        cx: &mut Context<Editor>,
 6890    ) -> Option<(String, Range<Anchor>)> {
 6891        if matches!(self.mode, EditorMode::SingleLine) {
 6892            return None;
 6893        }
 6894        if !EditorSettings::get_global(cx).selection_highlight {
 6895            return None;
 6896        }
 6897        if self.selections.count() != 1 || self.selections.line_mode {
 6898            return None;
 6899        }
 6900        let selection = self.selections.newest::<Point>(cx);
 6901        if selection.is_empty() || selection.start.row != selection.end.row {
 6902            return None;
 6903        }
 6904        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6905        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6906        let query = multi_buffer_snapshot
 6907            .text_for_range(selection_anchor_range.clone())
 6908            .collect::<String>();
 6909        if query.trim().is_empty() {
 6910            return None;
 6911        }
 6912        Some((query, selection_anchor_range))
 6913    }
 6914
 6915    fn update_selection_occurrence_highlights(
 6916        &mut self,
 6917        query_text: String,
 6918        query_range: Range<Anchor>,
 6919        multi_buffer_range_to_query: Range<Point>,
 6920        use_debounce: bool,
 6921        window: &mut Window,
 6922        cx: &mut Context<Editor>,
 6923    ) -> Task<()> {
 6924        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6925        cx.spawn_in(window, async move |editor, cx| {
 6926            if use_debounce {
 6927                cx.background_executor()
 6928                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6929                    .await;
 6930            }
 6931            let match_task = cx.background_spawn(async move {
 6932                let buffer_ranges = multi_buffer_snapshot
 6933                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6934                    .into_iter()
 6935                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6936                let mut match_ranges = Vec::new();
 6937                let Ok(regex) = project::search::SearchQuery::text(
 6938                    query_text.clone(),
 6939                    false,
 6940                    false,
 6941                    false,
 6942                    Default::default(),
 6943                    Default::default(),
 6944                    false,
 6945                    None,
 6946                ) else {
 6947                    return Vec::default();
 6948                };
 6949                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6950                    match_ranges.extend(
 6951                        regex
 6952                            .search(buffer_snapshot, Some(search_range.clone()))
 6953                            .await
 6954                            .into_iter()
 6955                            .filter_map(|match_range| {
 6956                                let match_start = buffer_snapshot
 6957                                    .anchor_after(search_range.start + match_range.start);
 6958                                let match_end = buffer_snapshot
 6959                                    .anchor_before(search_range.start + match_range.end);
 6960                                let match_anchor_range = Anchor::range_in_buffer(
 6961                                    excerpt_id,
 6962                                    buffer_snapshot.remote_id(),
 6963                                    match_start..match_end,
 6964                                );
 6965                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6966                            }),
 6967                    );
 6968                }
 6969                match_ranges
 6970            });
 6971            let match_ranges = match_task.await;
 6972            editor
 6973                .update_in(cx, |editor, _, cx| {
 6974                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6975                    if !match_ranges.is_empty() {
 6976                        editor.highlight_background::<SelectedTextHighlight>(
 6977                            &match_ranges,
 6978                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6979                            cx,
 6980                        )
 6981                    }
 6982                })
 6983                .log_err();
 6984        })
 6985    }
 6986
 6987    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6988        struct NewlineFold;
 6989        let type_id = std::any::TypeId::of::<NewlineFold>();
 6990        if !self.mode.is_single_line() {
 6991            return;
 6992        }
 6993        let snapshot = self.snapshot(window, cx);
 6994        if snapshot.buffer_snapshot.max_point().row == 0 {
 6995            return;
 6996        }
 6997        let task = cx.background_spawn(async move {
 6998            let new_newlines = snapshot
 6999                .buffer_chars_at(0)
 7000                .filter_map(|(c, i)| {
 7001                    if c == '\n' {
 7002                        Some(
 7003                            snapshot.buffer_snapshot.anchor_after(i)
 7004                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7005                        )
 7006                    } else {
 7007                        None
 7008                    }
 7009                })
 7010                .collect::<Vec<_>>();
 7011            let existing_newlines = snapshot
 7012                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7013                .filter_map(|fold| {
 7014                    if fold.placeholder.type_tag == Some(type_id) {
 7015                        Some(fold.range.start..fold.range.end)
 7016                    } else {
 7017                        None
 7018                    }
 7019                })
 7020                .collect::<Vec<_>>();
 7021
 7022            (new_newlines, existing_newlines)
 7023        });
 7024        self.folding_newlines = cx.spawn(async move |this, cx| {
 7025            let (new_newlines, existing_newlines) = task.await;
 7026            if new_newlines == existing_newlines {
 7027                return;
 7028            }
 7029            let placeholder = FoldPlaceholder {
 7030                render: Arc::new(move |_, _, cx| {
 7031                    div()
 7032                        .bg(cx.theme().status().hint_background)
 7033                        .border_b_1()
 7034                        .size_full()
 7035                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7036                        .border_color(cx.theme().status().hint)
 7037                        .child("\\n")
 7038                        .into_any()
 7039                }),
 7040                constrain_width: false,
 7041                merge_adjacent: false,
 7042                type_tag: Some(type_id),
 7043            };
 7044            let creases = new_newlines
 7045                .into_iter()
 7046                .map(|range| Crease::simple(range, placeholder.clone()))
 7047                .collect();
 7048            this.update(cx, |this, cx| {
 7049                this.display_map.update(cx, |display_map, cx| {
 7050                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7051                    display_map.fold(creases, cx);
 7052                });
 7053            })
 7054            .ok();
 7055        });
 7056    }
 7057
 7058    fn refresh_selected_text_highlights(
 7059        &mut self,
 7060        on_buffer_edit: bool,
 7061        window: &mut Window,
 7062        cx: &mut Context<Editor>,
 7063    ) {
 7064        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7065        else {
 7066            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7067            self.quick_selection_highlight_task.take();
 7068            self.debounced_selection_highlight_task.take();
 7069            return;
 7070        };
 7071        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7072        if on_buffer_edit
 7073            || self
 7074                .quick_selection_highlight_task
 7075                .as_ref()
 7076                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7077        {
 7078            let multi_buffer_visible_start = self
 7079                .scroll_manager
 7080                .anchor()
 7081                .anchor
 7082                .to_point(&multi_buffer_snapshot);
 7083            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7084                multi_buffer_visible_start
 7085                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7086                Bias::Left,
 7087            );
 7088            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7089            self.quick_selection_highlight_task = Some((
 7090                query_range.clone(),
 7091                self.update_selection_occurrence_highlights(
 7092                    query_text.clone(),
 7093                    query_range.clone(),
 7094                    multi_buffer_visible_range,
 7095                    false,
 7096                    window,
 7097                    cx,
 7098                ),
 7099            ));
 7100        }
 7101        if on_buffer_edit
 7102            || self
 7103                .debounced_selection_highlight_task
 7104                .as_ref()
 7105                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7106        {
 7107            let multi_buffer_start = multi_buffer_snapshot
 7108                .anchor_before(0)
 7109                .to_point(&multi_buffer_snapshot);
 7110            let multi_buffer_end = multi_buffer_snapshot
 7111                .anchor_after(multi_buffer_snapshot.len())
 7112                .to_point(&multi_buffer_snapshot);
 7113            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7114            self.debounced_selection_highlight_task = Some((
 7115                query_range.clone(),
 7116                self.update_selection_occurrence_highlights(
 7117                    query_text,
 7118                    query_range,
 7119                    multi_buffer_full_range,
 7120                    true,
 7121                    window,
 7122                    cx,
 7123                ),
 7124            ));
 7125        }
 7126    }
 7127
 7128    pub fn refresh_edit_prediction(
 7129        &mut self,
 7130        debounce: bool,
 7131        user_requested: bool,
 7132        window: &mut Window,
 7133        cx: &mut Context<Self>,
 7134    ) -> Option<()> {
 7135        if DisableAiSettings::get_global(cx).disable_ai {
 7136            return None;
 7137        }
 7138
 7139        let provider = self.edit_prediction_provider()?;
 7140        let cursor = self.selections.newest_anchor().head();
 7141        let (buffer, cursor_buffer_position) =
 7142            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7143
 7144        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7145            self.discard_edit_prediction(false, cx);
 7146            return None;
 7147        }
 7148
 7149        if !user_requested
 7150            && (!self.should_show_edit_predictions()
 7151                || !self.is_focused(window)
 7152                || buffer.read(cx).is_empty())
 7153        {
 7154            self.discard_edit_prediction(false, cx);
 7155            return None;
 7156        }
 7157
 7158        self.update_visible_edit_prediction(window, cx);
 7159        provider.refresh(
 7160            self.project.clone(),
 7161            buffer,
 7162            cursor_buffer_position,
 7163            debounce,
 7164            cx,
 7165        );
 7166        Some(())
 7167    }
 7168
 7169    fn show_edit_predictions_in_menu(&self) -> bool {
 7170        match self.edit_prediction_settings {
 7171            EditPredictionSettings::Disabled => false,
 7172            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7173        }
 7174    }
 7175
 7176    pub fn edit_predictions_enabled(&self) -> bool {
 7177        match self.edit_prediction_settings {
 7178            EditPredictionSettings::Disabled => false,
 7179            EditPredictionSettings::Enabled { .. } => true,
 7180        }
 7181    }
 7182
 7183    fn edit_prediction_requires_modifier(&self) -> bool {
 7184        match self.edit_prediction_settings {
 7185            EditPredictionSettings::Disabled => false,
 7186            EditPredictionSettings::Enabled {
 7187                preview_requires_modifier,
 7188                ..
 7189            } => preview_requires_modifier,
 7190        }
 7191    }
 7192
 7193    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7194        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7195            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7196            self.discard_edit_prediction(false, cx);
 7197        } else {
 7198            let selection = self.selections.newest_anchor();
 7199            let cursor = selection.head();
 7200
 7201            if let Some((buffer, cursor_buffer_position)) =
 7202                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7203            {
 7204                self.edit_prediction_settings =
 7205                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7206            }
 7207        }
 7208    }
 7209
 7210    fn edit_prediction_settings_at_position(
 7211        &self,
 7212        buffer: &Entity<Buffer>,
 7213        buffer_position: language::Anchor,
 7214        cx: &App,
 7215    ) -> EditPredictionSettings {
 7216        if !self.mode.is_full()
 7217            || !self.show_edit_predictions_override.unwrap_or(true)
 7218            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7219        {
 7220            return EditPredictionSettings::Disabled;
 7221        }
 7222
 7223        let buffer = buffer.read(cx);
 7224
 7225        let file = buffer.file();
 7226
 7227        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7228            return EditPredictionSettings::Disabled;
 7229        };
 7230
 7231        let by_provider = matches!(
 7232            self.menu_edit_predictions_policy,
 7233            MenuEditPredictionsPolicy::ByProvider
 7234        );
 7235
 7236        let show_in_menu = by_provider
 7237            && self
 7238                .edit_prediction_provider
 7239                .as_ref()
 7240                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7241
 7242        let preview_requires_modifier =
 7243            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7244
 7245        EditPredictionSettings::Enabled {
 7246            show_in_menu,
 7247            preview_requires_modifier,
 7248        }
 7249    }
 7250
 7251    fn should_show_edit_predictions(&self) -> bool {
 7252        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7253    }
 7254
 7255    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7256        matches!(
 7257            self.edit_prediction_preview,
 7258            EditPredictionPreview::Active { .. }
 7259        )
 7260    }
 7261
 7262    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7263        let cursor = self.selections.newest_anchor().head();
 7264        if let Some((buffer, cursor_position)) =
 7265            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7266        {
 7267            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7268        } else {
 7269            false
 7270        }
 7271    }
 7272
 7273    pub fn supports_minimap(&self, cx: &App) -> bool {
 7274        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7275    }
 7276
 7277    fn edit_predictions_enabled_in_buffer(
 7278        &self,
 7279        buffer: &Entity<Buffer>,
 7280        buffer_position: language::Anchor,
 7281        cx: &App,
 7282    ) -> bool {
 7283        maybe!({
 7284            if self.read_only(cx) {
 7285                return Some(false);
 7286            }
 7287            let provider = self.edit_prediction_provider()?;
 7288            if !provider.is_enabled(buffer, buffer_position, cx) {
 7289                return Some(false);
 7290            }
 7291            let buffer = buffer.read(cx);
 7292            let Some(file) = buffer.file() else {
 7293                return Some(true);
 7294            };
 7295            let settings = all_language_settings(Some(file), cx);
 7296            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7297        })
 7298        .unwrap_or(false)
 7299    }
 7300
 7301    fn cycle_edit_prediction(
 7302        &mut self,
 7303        direction: Direction,
 7304        window: &mut Window,
 7305        cx: &mut Context<Self>,
 7306    ) -> Option<()> {
 7307        let provider = self.edit_prediction_provider()?;
 7308        let cursor = self.selections.newest_anchor().head();
 7309        let (buffer, cursor_buffer_position) =
 7310            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7311        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7312            return None;
 7313        }
 7314
 7315        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7316        self.update_visible_edit_prediction(window, cx);
 7317
 7318        Some(())
 7319    }
 7320
 7321    pub fn show_edit_prediction(
 7322        &mut self,
 7323        _: &ShowEditPrediction,
 7324        window: &mut Window,
 7325        cx: &mut Context<Self>,
 7326    ) {
 7327        if !self.has_active_edit_prediction() {
 7328            self.refresh_edit_prediction(false, true, window, cx);
 7329            return;
 7330        }
 7331
 7332        self.update_visible_edit_prediction(window, cx);
 7333    }
 7334
 7335    pub fn display_cursor_names(
 7336        &mut self,
 7337        _: &DisplayCursorNames,
 7338        window: &mut Window,
 7339        cx: &mut Context<Self>,
 7340    ) {
 7341        self.show_cursor_names(window, cx);
 7342    }
 7343
 7344    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7345        self.show_cursor_names = true;
 7346        cx.notify();
 7347        cx.spawn_in(window, async move |this, cx| {
 7348            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7349            this.update(cx, |this, cx| {
 7350                this.show_cursor_names = false;
 7351                cx.notify()
 7352            })
 7353            .ok()
 7354        })
 7355        .detach();
 7356    }
 7357
 7358    pub fn next_edit_prediction(
 7359        &mut self,
 7360        _: &NextEditPrediction,
 7361        window: &mut Window,
 7362        cx: &mut Context<Self>,
 7363    ) {
 7364        if self.has_active_edit_prediction() {
 7365            self.cycle_edit_prediction(Direction::Next, window, cx);
 7366        } else {
 7367            let is_copilot_disabled = self
 7368                .refresh_edit_prediction(false, true, window, cx)
 7369                .is_none();
 7370            if is_copilot_disabled {
 7371                cx.propagate();
 7372            }
 7373        }
 7374    }
 7375
 7376    pub fn previous_edit_prediction(
 7377        &mut self,
 7378        _: &PreviousEditPrediction,
 7379        window: &mut Window,
 7380        cx: &mut Context<Self>,
 7381    ) {
 7382        if self.has_active_edit_prediction() {
 7383            self.cycle_edit_prediction(Direction::Prev, 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 accept_edit_prediction(
 7395        &mut self,
 7396        _: &AcceptEditPrediction,
 7397        window: &mut Window,
 7398        cx: &mut Context<Self>,
 7399    ) {
 7400        if self.show_edit_predictions_in_menu() {
 7401            self.hide_context_menu(window, cx);
 7402        }
 7403
 7404        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7405            return;
 7406        };
 7407
 7408        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7409
 7410        match &active_edit_prediction.completion {
 7411            EditPrediction::Move { target, .. } => {
 7412                let target = *target;
 7413
 7414                if let Some(position_map) = &self.last_position_map {
 7415                    if position_map
 7416                        .visible_row_range
 7417                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7418                        || !self.edit_prediction_requires_modifier()
 7419                    {
 7420                        self.unfold_ranges(&[target..target], true, false, cx);
 7421                        // Note that this is also done in vim's handler of the Tab action.
 7422                        self.change_selections(
 7423                            SelectionEffects::scroll(Autoscroll::newest()),
 7424                            window,
 7425                            cx,
 7426                            |selections| {
 7427                                selections.select_anchor_ranges([target..target]);
 7428                            },
 7429                        );
 7430                        self.clear_row_highlights::<EditPredictionPreview>();
 7431
 7432                        self.edit_prediction_preview
 7433                            .set_previous_scroll_position(None);
 7434                    } else {
 7435                        self.edit_prediction_preview
 7436                            .set_previous_scroll_position(Some(
 7437                                position_map.snapshot.scroll_anchor,
 7438                            ));
 7439
 7440                        self.highlight_rows::<EditPredictionPreview>(
 7441                            target..target,
 7442                            cx.theme().colors().editor_highlighted_line_background,
 7443                            RowHighlightOptions {
 7444                                autoscroll: true,
 7445                                ..Default::default()
 7446                            },
 7447                            cx,
 7448                        );
 7449                        self.request_autoscroll(Autoscroll::fit(), cx);
 7450                    }
 7451                }
 7452            }
 7453            EditPrediction::Edit { edits, .. } => {
 7454                if let Some(provider) = self.edit_prediction_provider() {
 7455                    provider.accept(cx);
 7456                }
 7457
 7458                // Store the transaction ID and selections before applying the edit
 7459                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7460
 7461                let snapshot = self.buffer.read(cx).snapshot(cx);
 7462                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7463
 7464                self.buffer.update(cx, |buffer, cx| {
 7465                    buffer.edit(edits.iter().cloned(), None, cx)
 7466                });
 7467
 7468                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7469                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7470                });
 7471
 7472                let selections = self.selections.disjoint_anchors_arc();
 7473                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7474                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7475                    if has_new_transaction {
 7476                        self.selection_history
 7477                            .insert_transaction(transaction_id_now, selections);
 7478                    }
 7479                }
 7480
 7481                self.update_visible_edit_prediction(window, cx);
 7482                if self.active_edit_prediction.is_none() {
 7483                    self.refresh_edit_prediction(true, true, window, cx);
 7484                }
 7485
 7486                cx.notify();
 7487            }
 7488        }
 7489
 7490        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7491    }
 7492
 7493    pub fn accept_partial_edit_prediction(
 7494        &mut self,
 7495        _: &AcceptPartialEditPrediction,
 7496        window: &mut Window,
 7497        cx: &mut Context<Self>,
 7498    ) {
 7499        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7500            return;
 7501        };
 7502        if self.selections.count() != 1 {
 7503            return;
 7504        }
 7505
 7506        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7507
 7508        match &active_edit_prediction.completion {
 7509            EditPrediction::Move { target, .. } => {
 7510                let target = *target;
 7511                self.change_selections(
 7512                    SelectionEffects::scroll(Autoscroll::newest()),
 7513                    window,
 7514                    cx,
 7515                    |selections| {
 7516                        selections.select_anchor_ranges([target..target]);
 7517                    },
 7518                );
 7519            }
 7520            EditPrediction::Edit { edits, .. } => {
 7521                // Find an insertion that starts at the cursor position.
 7522                let snapshot = self.buffer.read(cx).snapshot(cx);
 7523                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7524                let insertion = edits.iter().find_map(|(range, text)| {
 7525                    let range = range.to_offset(&snapshot);
 7526                    if range.is_empty() && range.start == cursor_offset {
 7527                        Some(text)
 7528                    } else {
 7529                        None
 7530                    }
 7531                });
 7532
 7533                if let Some(text) = insertion {
 7534                    let mut partial_completion = text
 7535                        .chars()
 7536                        .by_ref()
 7537                        .take_while(|c| c.is_alphabetic())
 7538                        .collect::<String>();
 7539                    if partial_completion.is_empty() {
 7540                        partial_completion = text
 7541                            .chars()
 7542                            .by_ref()
 7543                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7544                            .collect::<String>();
 7545                    }
 7546
 7547                    cx.emit(EditorEvent::InputHandled {
 7548                        utf16_range_to_replace: None,
 7549                        text: partial_completion.clone().into(),
 7550                    });
 7551
 7552                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7553
 7554                    self.refresh_edit_prediction(true, true, window, cx);
 7555                    cx.notify();
 7556                } else {
 7557                    self.accept_edit_prediction(&Default::default(), window, cx);
 7558                }
 7559            }
 7560        }
 7561    }
 7562
 7563    fn discard_edit_prediction(
 7564        &mut self,
 7565        should_report_edit_prediction_event: bool,
 7566        cx: &mut Context<Self>,
 7567    ) -> bool {
 7568        if should_report_edit_prediction_event {
 7569            let completion_id = self
 7570                .active_edit_prediction
 7571                .as_ref()
 7572                .and_then(|active_completion| active_completion.completion_id.clone());
 7573
 7574            self.report_edit_prediction_event(completion_id, false, cx);
 7575        }
 7576
 7577        if let Some(provider) = self.edit_prediction_provider() {
 7578            provider.discard(cx);
 7579        }
 7580
 7581        self.take_active_edit_prediction(cx)
 7582    }
 7583
 7584    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7585        let Some(provider) = self.edit_prediction_provider() else {
 7586            return;
 7587        };
 7588
 7589        let Some((_, buffer, _)) = self
 7590            .buffer
 7591            .read(cx)
 7592            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7593        else {
 7594            return;
 7595        };
 7596
 7597        let extension = buffer
 7598            .read(cx)
 7599            .file()
 7600            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7601
 7602        let event_type = match accepted {
 7603            true => "Edit Prediction Accepted",
 7604            false => "Edit Prediction Discarded",
 7605        };
 7606        telemetry::event!(
 7607            event_type,
 7608            provider = provider.name(),
 7609            prediction_id = id,
 7610            suggestion_accepted = accepted,
 7611            file_extension = extension,
 7612        );
 7613    }
 7614
 7615    pub fn has_active_edit_prediction(&self) -> bool {
 7616        self.active_edit_prediction.is_some()
 7617    }
 7618
 7619    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7620        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7621            return false;
 7622        };
 7623
 7624        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7625        self.clear_highlights::<EditPredictionHighlight>(cx);
 7626        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7627        true
 7628    }
 7629
 7630    /// Returns true when we're displaying the edit prediction popover below the cursor
 7631    /// like we are not previewing and the LSP autocomplete menu is visible
 7632    /// or we are in `when_holding_modifier` mode.
 7633    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7634        if self.edit_prediction_preview_is_active()
 7635            || !self.show_edit_predictions_in_menu()
 7636            || !self.edit_predictions_enabled()
 7637        {
 7638            return false;
 7639        }
 7640
 7641        if self.has_visible_completions_menu() {
 7642            return true;
 7643        }
 7644
 7645        has_completion && self.edit_prediction_requires_modifier()
 7646    }
 7647
 7648    fn handle_modifiers_changed(
 7649        &mut self,
 7650        modifiers: Modifiers,
 7651        position_map: &PositionMap,
 7652        window: &mut Window,
 7653        cx: &mut Context<Self>,
 7654    ) {
 7655        if self.show_edit_predictions_in_menu() {
 7656            self.update_edit_prediction_preview(&modifiers, window, cx);
 7657        }
 7658
 7659        self.update_selection_mode(&modifiers, position_map, window, cx);
 7660
 7661        let mouse_position = window.mouse_position();
 7662        if !position_map.text_hitbox.is_hovered(window) {
 7663            return;
 7664        }
 7665
 7666        self.update_hovered_link(
 7667            position_map.point_for_position(mouse_position),
 7668            &position_map.snapshot,
 7669            modifiers,
 7670            window,
 7671            cx,
 7672        )
 7673    }
 7674
 7675    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7676        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7677        if invert {
 7678            match multi_cursor_setting {
 7679                MultiCursorModifier::Alt => modifiers.alt,
 7680                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7681            }
 7682        } else {
 7683            match multi_cursor_setting {
 7684                MultiCursorModifier::Alt => modifiers.secondary(),
 7685                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7686            }
 7687        }
 7688    }
 7689
 7690    fn columnar_selection_mode(
 7691        modifiers: &Modifiers,
 7692        cx: &mut Context<Self>,
 7693    ) -> Option<ColumnarMode> {
 7694        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7695            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7696                Some(ColumnarMode::FromMouse)
 7697            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7698                Some(ColumnarMode::FromSelection)
 7699            } else {
 7700                None
 7701            }
 7702        } else {
 7703            None
 7704        }
 7705    }
 7706
 7707    fn update_selection_mode(
 7708        &mut self,
 7709        modifiers: &Modifiers,
 7710        position_map: &PositionMap,
 7711        window: &mut Window,
 7712        cx: &mut Context<Self>,
 7713    ) {
 7714        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7715            return;
 7716        };
 7717        if self.selections.pending_anchor().is_none() {
 7718            return;
 7719        }
 7720
 7721        let mouse_position = window.mouse_position();
 7722        let point_for_position = position_map.point_for_position(mouse_position);
 7723        let position = point_for_position.previous_valid;
 7724
 7725        self.select(
 7726            SelectPhase::BeginColumnar {
 7727                position,
 7728                reset: false,
 7729                mode,
 7730                goal_column: point_for_position.exact_unclipped.column(),
 7731            },
 7732            window,
 7733            cx,
 7734        );
 7735    }
 7736
 7737    fn update_edit_prediction_preview(
 7738        &mut self,
 7739        modifiers: &Modifiers,
 7740        window: &mut Window,
 7741        cx: &mut Context<Self>,
 7742    ) {
 7743        let mut modifiers_held = false;
 7744        if let Some(accept_keystroke) = self
 7745            .accept_edit_prediction_keybind(false, window, cx)
 7746            .keystroke()
 7747        {
 7748            modifiers_held = modifiers_held
 7749                || (accept_keystroke.modifiers() == modifiers
 7750                    && accept_keystroke.modifiers().modified());
 7751        };
 7752        if let Some(accept_partial_keystroke) = self
 7753            .accept_edit_prediction_keybind(true, window, cx)
 7754            .keystroke()
 7755        {
 7756            modifiers_held = modifiers_held
 7757                || (accept_partial_keystroke.modifiers() == modifiers
 7758                    && accept_partial_keystroke.modifiers().modified());
 7759        }
 7760
 7761        if modifiers_held {
 7762            if matches!(
 7763                self.edit_prediction_preview,
 7764                EditPredictionPreview::Inactive { .. }
 7765            ) {
 7766                self.edit_prediction_preview = EditPredictionPreview::Active {
 7767                    previous_scroll_position: None,
 7768                    since: Instant::now(),
 7769                };
 7770
 7771                self.update_visible_edit_prediction(window, cx);
 7772                cx.notify();
 7773            }
 7774        } else if let EditPredictionPreview::Active {
 7775            previous_scroll_position,
 7776            since,
 7777        } = self.edit_prediction_preview
 7778        {
 7779            if let (Some(previous_scroll_position), Some(position_map)) =
 7780                (previous_scroll_position, self.last_position_map.as_ref())
 7781            {
 7782                self.set_scroll_position(
 7783                    previous_scroll_position
 7784                        .scroll_position(&position_map.snapshot.display_snapshot),
 7785                    window,
 7786                    cx,
 7787                );
 7788            }
 7789
 7790            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7791                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7792            };
 7793            self.clear_row_highlights::<EditPredictionPreview>();
 7794            self.update_visible_edit_prediction(window, cx);
 7795            cx.notify();
 7796        }
 7797    }
 7798
 7799    fn update_visible_edit_prediction(
 7800        &mut self,
 7801        _window: &mut Window,
 7802        cx: &mut Context<Self>,
 7803    ) -> Option<()> {
 7804        if DisableAiSettings::get_global(cx).disable_ai {
 7805            return None;
 7806        }
 7807
 7808        if self.ime_transaction.is_some() {
 7809            self.discard_edit_prediction(false, cx);
 7810            return None;
 7811        }
 7812
 7813        let selection = self.selections.newest_anchor();
 7814        let cursor = selection.head();
 7815        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7816        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7817        let excerpt_id = cursor.excerpt_id;
 7818
 7819        let show_in_menu = self.show_edit_predictions_in_menu();
 7820        let completions_menu_has_precedence = !show_in_menu
 7821            && (self.context_menu.borrow().is_some()
 7822                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7823
 7824        if completions_menu_has_precedence
 7825            || !offset_selection.is_empty()
 7826            || self
 7827                .active_edit_prediction
 7828                .as_ref()
 7829                .is_some_and(|completion| {
 7830                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7831                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7832                    !invalidation_range.contains(&offset_selection.head())
 7833                })
 7834        {
 7835            self.discard_edit_prediction(false, cx);
 7836            return None;
 7837        }
 7838
 7839        self.take_active_edit_prediction(cx);
 7840        let Some(provider) = self.edit_prediction_provider() else {
 7841            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7842            return None;
 7843        };
 7844
 7845        let (buffer, cursor_buffer_position) =
 7846            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7847
 7848        self.edit_prediction_settings =
 7849            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7850
 7851        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7852            self.discard_edit_prediction(false, cx);
 7853            return None;
 7854        };
 7855
 7856        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7857
 7858        if self.edit_prediction_indent_conflict {
 7859            let cursor_point = cursor.to_point(&multibuffer);
 7860
 7861            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7862
 7863            if let Some((_, indent)) = indents.iter().next()
 7864                && indent.len == cursor_point.column
 7865            {
 7866                self.edit_prediction_indent_conflict = false;
 7867            }
 7868        }
 7869
 7870        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7871        let edits = edit_prediction
 7872            .edits
 7873            .into_iter()
 7874            .flat_map(|(range, new_text)| {
 7875                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7876                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7877                Some((start..end, new_text))
 7878            })
 7879            .collect::<Vec<_>>();
 7880        if edits.is_empty() {
 7881            return None;
 7882        }
 7883
 7884        let first_edit_start = edits.first().unwrap().0.start;
 7885        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7886        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7887
 7888        let last_edit_end = edits.last().unwrap().0.end;
 7889        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7890        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7891
 7892        let cursor_row = cursor.to_point(&multibuffer).row;
 7893
 7894        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7895
 7896        let mut inlay_ids = Vec::new();
 7897        let invalidation_row_range;
 7898        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7899            Some(cursor_row..edit_end_row)
 7900        } else if cursor_row > edit_end_row {
 7901            Some(edit_start_row..cursor_row)
 7902        } else {
 7903            None
 7904        };
 7905        let supports_jump = self
 7906            .edit_prediction_provider
 7907            .as_ref()
 7908            .map(|provider| provider.provider.supports_jump_to_edit())
 7909            .unwrap_or(true);
 7910
 7911        let is_move = supports_jump
 7912            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7913        let completion = if is_move {
 7914            invalidation_row_range =
 7915                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7916            let target = first_edit_start;
 7917            EditPrediction::Move { target, snapshot }
 7918        } else {
 7919            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7920                && !self.edit_predictions_hidden_for_vim_mode;
 7921
 7922            if show_completions_in_buffer {
 7923                if edits
 7924                    .iter()
 7925                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7926                {
 7927                    let mut inlays = Vec::new();
 7928                    for (range, new_text) in &edits {
 7929                        let inlay = Inlay::edit_prediction(
 7930                            post_inc(&mut self.next_inlay_id),
 7931                            range.start,
 7932                            new_text.as_str(),
 7933                        );
 7934                        inlay_ids.push(inlay.id);
 7935                        inlays.push(inlay);
 7936                    }
 7937
 7938                    self.splice_inlays(&[], inlays, cx);
 7939                } else {
 7940                    let background_color = cx.theme().status().deleted_background;
 7941                    self.highlight_text::<EditPredictionHighlight>(
 7942                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7943                        HighlightStyle {
 7944                            background_color: Some(background_color),
 7945                            ..Default::default()
 7946                        },
 7947                        cx,
 7948                    );
 7949                }
 7950            }
 7951
 7952            invalidation_row_range = edit_start_row..edit_end_row;
 7953
 7954            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7955                if provider.show_tab_accept_marker() {
 7956                    EditDisplayMode::TabAccept
 7957                } else {
 7958                    EditDisplayMode::Inline
 7959                }
 7960            } else {
 7961                EditDisplayMode::DiffPopover
 7962            };
 7963
 7964            EditPrediction::Edit {
 7965                edits,
 7966                edit_preview: edit_prediction.edit_preview,
 7967                display_mode,
 7968                snapshot,
 7969            }
 7970        };
 7971
 7972        let invalidation_range = multibuffer
 7973            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7974            ..multibuffer.anchor_after(Point::new(
 7975                invalidation_row_range.end,
 7976                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7977            ));
 7978
 7979        self.stale_edit_prediction_in_menu = None;
 7980        self.active_edit_prediction = Some(EditPredictionState {
 7981            inlay_ids,
 7982            completion,
 7983            completion_id: edit_prediction.id,
 7984            invalidation_range,
 7985        });
 7986
 7987        cx.notify();
 7988
 7989        Some(())
 7990    }
 7991
 7992    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7993        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7994    }
 7995
 7996    fn clear_tasks(&mut self) {
 7997        self.tasks.clear()
 7998    }
 7999
 8000    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8001        if self.tasks.insert(key, value).is_some() {
 8002            // This case should hopefully be rare, but just in case...
 8003            log::error!(
 8004                "multiple different run targets found on a single line, only the last target will be rendered"
 8005            )
 8006        }
 8007    }
 8008
 8009    /// Get all display points of breakpoints that will be rendered within editor
 8010    ///
 8011    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8012    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8013    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8014    fn active_breakpoints(
 8015        &self,
 8016        range: Range<DisplayRow>,
 8017        window: &mut Window,
 8018        cx: &mut Context<Self>,
 8019    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8020        let mut breakpoint_display_points = HashMap::default();
 8021
 8022        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8023            return breakpoint_display_points;
 8024        };
 8025
 8026        let snapshot = self.snapshot(window, cx);
 8027
 8028        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8029        let Some(project) = self.project() else {
 8030            return breakpoint_display_points;
 8031        };
 8032
 8033        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8034            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8035
 8036        for (buffer_snapshot, range, excerpt_id) in
 8037            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8038        {
 8039            let Some(buffer) = project
 8040                .read(cx)
 8041                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8042            else {
 8043                continue;
 8044            };
 8045            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8046                &buffer,
 8047                Some(
 8048                    buffer_snapshot.anchor_before(range.start)
 8049                        ..buffer_snapshot.anchor_after(range.end),
 8050                ),
 8051                buffer_snapshot,
 8052                cx,
 8053            );
 8054            for (breakpoint, state) in breakpoints {
 8055                let multi_buffer_anchor =
 8056                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8057                let position = multi_buffer_anchor
 8058                    .to_point(multi_buffer_snapshot)
 8059                    .to_display_point(&snapshot);
 8060
 8061                breakpoint_display_points.insert(
 8062                    position.row(),
 8063                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8064                );
 8065            }
 8066        }
 8067
 8068        breakpoint_display_points
 8069    }
 8070
 8071    fn breakpoint_context_menu(
 8072        &self,
 8073        anchor: Anchor,
 8074        window: &mut Window,
 8075        cx: &mut Context<Self>,
 8076    ) -> Entity<ui::ContextMenu> {
 8077        let weak_editor = cx.weak_entity();
 8078        let focus_handle = self.focus_handle(cx);
 8079
 8080        let row = self
 8081            .buffer
 8082            .read(cx)
 8083            .snapshot(cx)
 8084            .summary_for_anchor::<Point>(&anchor)
 8085            .row;
 8086
 8087        let breakpoint = self
 8088            .breakpoint_at_row(row, window, cx)
 8089            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8090
 8091        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8092            "Edit Log Breakpoint"
 8093        } else {
 8094            "Set Log Breakpoint"
 8095        };
 8096
 8097        let condition_breakpoint_msg = if breakpoint
 8098            .as_ref()
 8099            .is_some_and(|bp| bp.1.condition.is_some())
 8100        {
 8101            "Edit Condition Breakpoint"
 8102        } else {
 8103            "Set Condition Breakpoint"
 8104        };
 8105
 8106        let hit_condition_breakpoint_msg = if breakpoint
 8107            .as_ref()
 8108            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8109        {
 8110            "Edit Hit Condition Breakpoint"
 8111        } else {
 8112            "Set Hit Condition Breakpoint"
 8113        };
 8114
 8115        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8116            "Unset Breakpoint"
 8117        } else {
 8118            "Set Breakpoint"
 8119        };
 8120
 8121        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8122
 8123        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8124            BreakpointState::Enabled => Some("Disable"),
 8125            BreakpointState::Disabled => Some("Enable"),
 8126        });
 8127
 8128        let (anchor, breakpoint) =
 8129            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8130
 8131        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8132            menu.on_blur_subscription(Subscription::new(|| {}))
 8133                .context(focus_handle)
 8134                .when(run_to_cursor, |this| {
 8135                    let weak_editor = weak_editor.clone();
 8136                    this.entry("Run to cursor", None, move |window, cx| {
 8137                        weak_editor
 8138                            .update(cx, |editor, cx| {
 8139                                editor.change_selections(
 8140                                    SelectionEffects::no_scroll(),
 8141                                    window,
 8142                                    cx,
 8143                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8144                                );
 8145                            })
 8146                            .ok();
 8147
 8148                        window.dispatch_action(Box::new(RunToCursor), cx);
 8149                    })
 8150                    .separator()
 8151                })
 8152                .when_some(toggle_state_msg, |this, msg| {
 8153                    this.entry(msg, None, {
 8154                        let weak_editor = weak_editor.clone();
 8155                        let breakpoint = breakpoint.clone();
 8156                        move |_window, cx| {
 8157                            weak_editor
 8158                                .update(cx, |this, cx| {
 8159                                    this.edit_breakpoint_at_anchor(
 8160                                        anchor,
 8161                                        breakpoint.as_ref().clone(),
 8162                                        BreakpointEditAction::InvertState,
 8163                                        cx,
 8164                                    );
 8165                                })
 8166                                .log_err();
 8167                        }
 8168                    })
 8169                })
 8170                .entry(set_breakpoint_msg, None, {
 8171                    let weak_editor = weak_editor.clone();
 8172                    let breakpoint = breakpoint.clone();
 8173                    move |_window, cx| {
 8174                        weak_editor
 8175                            .update(cx, |this, cx| {
 8176                                this.edit_breakpoint_at_anchor(
 8177                                    anchor,
 8178                                    breakpoint.as_ref().clone(),
 8179                                    BreakpointEditAction::Toggle,
 8180                                    cx,
 8181                                );
 8182                            })
 8183                            .log_err();
 8184                    }
 8185                })
 8186                .entry(log_breakpoint_msg, None, {
 8187                    let breakpoint = breakpoint.clone();
 8188                    let weak_editor = weak_editor.clone();
 8189                    move |window, cx| {
 8190                        weak_editor
 8191                            .update(cx, |this, cx| {
 8192                                this.add_edit_breakpoint_block(
 8193                                    anchor,
 8194                                    breakpoint.as_ref(),
 8195                                    BreakpointPromptEditAction::Log,
 8196                                    window,
 8197                                    cx,
 8198                                );
 8199                            })
 8200                            .log_err();
 8201                    }
 8202                })
 8203                .entry(condition_breakpoint_msg, None, {
 8204                    let breakpoint = breakpoint.clone();
 8205                    let weak_editor = weak_editor.clone();
 8206                    move |window, cx| {
 8207                        weak_editor
 8208                            .update(cx, |this, cx| {
 8209                                this.add_edit_breakpoint_block(
 8210                                    anchor,
 8211                                    breakpoint.as_ref(),
 8212                                    BreakpointPromptEditAction::Condition,
 8213                                    window,
 8214                                    cx,
 8215                                );
 8216                            })
 8217                            .log_err();
 8218                    }
 8219                })
 8220                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8221                    weak_editor
 8222                        .update(cx, |this, cx| {
 8223                            this.add_edit_breakpoint_block(
 8224                                anchor,
 8225                                breakpoint.as_ref(),
 8226                                BreakpointPromptEditAction::HitCondition,
 8227                                window,
 8228                                cx,
 8229                            );
 8230                        })
 8231                        .log_err();
 8232                })
 8233        })
 8234    }
 8235
 8236    fn render_breakpoint(
 8237        &self,
 8238        position: Anchor,
 8239        row: DisplayRow,
 8240        breakpoint: &Breakpoint,
 8241        state: Option<BreakpointSessionState>,
 8242        cx: &mut Context<Self>,
 8243    ) -> IconButton {
 8244        let is_rejected = state.is_some_and(|s| !s.verified);
 8245        // Is it a breakpoint that shows up when hovering over gutter?
 8246        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8247            (false, false),
 8248            |PhantomBreakpointIndicator {
 8249                 is_active,
 8250                 display_row,
 8251                 collides_with_existing_breakpoint,
 8252             }| {
 8253                (
 8254                    is_active && display_row == row,
 8255                    collides_with_existing_breakpoint,
 8256                )
 8257            },
 8258        );
 8259
 8260        let (color, icon) = {
 8261            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8262                (false, false) => ui::IconName::DebugBreakpoint,
 8263                (true, false) => ui::IconName::DebugLogBreakpoint,
 8264                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8265                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8266            };
 8267
 8268            let color = if is_phantom {
 8269                Color::Hint
 8270            } else if is_rejected {
 8271                Color::Disabled
 8272            } else {
 8273                Color::Debugger
 8274            };
 8275
 8276            (color, icon)
 8277        };
 8278
 8279        let breakpoint = Arc::from(breakpoint.clone());
 8280
 8281        let alt_as_text = gpui::Keystroke {
 8282            modifiers: Modifiers::secondary_key(),
 8283            ..Default::default()
 8284        };
 8285        let primary_action_text = if breakpoint.is_disabled() {
 8286            "Enable breakpoint"
 8287        } else if is_phantom && !collides_with_existing {
 8288            "Set breakpoint"
 8289        } else {
 8290            "Unset breakpoint"
 8291        };
 8292        let focus_handle = self.focus_handle.clone();
 8293
 8294        let meta = if is_rejected {
 8295            SharedString::from("No executable code is associated with this line.")
 8296        } else if collides_with_existing && !breakpoint.is_disabled() {
 8297            SharedString::from(format!(
 8298                "{alt_as_text}-click to disable,\nright-click for more options."
 8299            ))
 8300        } else {
 8301            SharedString::from("Right-click for more options.")
 8302        };
 8303        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8304            .icon_size(IconSize::XSmall)
 8305            .size(ui::ButtonSize::None)
 8306            .when(is_rejected, |this| {
 8307                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8308            })
 8309            .icon_color(color)
 8310            .style(ButtonStyle::Transparent)
 8311            .on_click(cx.listener({
 8312                move |editor, event: &ClickEvent, window, cx| {
 8313                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8314                        BreakpointEditAction::InvertState
 8315                    } else {
 8316                        BreakpointEditAction::Toggle
 8317                    };
 8318
 8319                    window.focus(&editor.focus_handle(cx));
 8320                    editor.edit_breakpoint_at_anchor(
 8321                        position,
 8322                        breakpoint.as_ref().clone(),
 8323                        edit_action,
 8324                        cx,
 8325                    );
 8326                }
 8327            }))
 8328            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8329                editor.set_breakpoint_context_menu(
 8330                    row,
 8331                    Some(position),
 8332                    event.position(),
 8333                    window,
 8334                    cx,
 8335                );
 8336            }))
 8337            .tooltip(move |window, cx| {
 8338                Tooltip::with_meta_in(
 8339                    primary_action_text,
 8340                    Some(&ToggleBreakpoint),
 8341                    meta.clone(),
 8342                    &focus_handle,
 8343                    window,
 8344                    cx,
 8345                )
 8346            })
 8347    }
 8348
 8349    fn build_tasks_context(
 8350        project: &Entity<Project>,
 8351        buffer: &Entity<Buffer>,
 8352        buffer_row: u32,
 8353        tasks: &Arc<RunnableTasks>,
 8354        cx: &mut Context<Self>,
 8355    ) -> Task<Option<task::TaskContext>> {
 8356        let position = Point::new(buffer_row, tasks.column);
 8357        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8358        let location = Location {
 8359            buffer: buffer.clone(),
 8360            range: range_start..range_start,
 8361        };
 8362        // Fill in the environmental variables from the tree-sitter captures
 8363        let mut captured_task_variables = TaskVariables::default();
 8364        for (capture_name, value) in tasks.extra_variables.clone() {
 8365            captured_task_variables.insert(
 8366                task::VariableName::Custom(capture_name.into()),
 8367                value.clone(),
 8368            );
 8369        }
 8370        project.update(cx, |project, cx| {
 8371            project.task_store().update(cx, |task_store, cx| {
 8372                task_store.task_context_for_location(captured_task_variables, location, cx)
 8373            })
 8374        })
 8375    }
 8376
 8377    pub fn spawn_nearest_task(
 8378        &mut self,
 8379        action: &SpawnNearestTask,
 8380        window: &mut Window,
 8381        cx: &mut Context<Self>,
 8382    ) {
 8383        let Some((workspace, _)) = self.workspace.clone() else {
 8384            return;
 8385        };
 8386        let Some(project) = self.project.clone() else {
 8387            return;
 8388        };
 8389
 8390        // Try to find a closest, enclosing node using tree-sitter that has a task
 8391        let Some((buffer, buffer_row, tasks)) = self
 8392            .find_enclosing_node_task(cx)
 8393            // Or find the task that's closest in row-distance.
 8394            .or_else(|| self.find_closest_task(cx))
 8395        else {
 8396            return;
 8397        };
 8398
 8399        let reveal_strategy = action.reveal;
 8400        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8401        cx.spawn_in(window, async move |_, cx| {
 8402            let context = task_context.await?;
 8403            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8404
 8405            let resolved = &mut resolved_task.resolved;
 8406            resolved.reveal = reveal_strategy;
 8407
 8408            workspace
 8409                .update_in(cx, |workspace, window, cx| {
 8410                    workspace.schedule_resolved_task(
 8411                        task_source_kind,
 8412                        resolved_task,
 8413                        false,
 8414                        window,
 8415                        cx,
 8416                    );
 8417                })
 8418                .ok()
 8419        })
 8420        .detach();
 8421    }
 8422
 8423    fn find_closest_task(
 8424        &mut self,
 8425        cx: &mut Context<Self>,
 8426    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8427        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8428
 8429        let ((buffer_id, row), tasks) = self
 8430            .tasks
 8431            .iter()
 8432            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8433
 8434        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8435        let tasks = Arc::new(tasks.to_owned());
 8436        Some((buffer, *row, tasks))
 8437    }
 8438
 8439    fn find_enclosing_node_task(
 8440        &mut self,
 8441        cx: &mut Context<Self>,
 8442    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8443        let snapshot = self.buffer.read(cx).snapshot(cx);
 8444        let offset = self.selections.newest::<usize>(cx).head();
 8445        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8446        let buffer_id = excerpt.buffer().remote_id();
 8447
 8448        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8449        let mut cursor = layer.node().walk();
 8450
 8451        while cursor.goto_first_child_for_byte(offset).is_some() {
 8452            if cursor.node().end_byte() == offset {
 8453                cursor.goto_next_sibling();
 8454            }
 8455        }
 8456
 8457        // Ascend to the smallest ancestor that contains the range and has a task.
 8458        loop {
 8459            let node = cursor.node();
 8460            let node_range = node.byte_range();
 8461            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8462
 8463            // Check if this node contains our offset
 8464            if node_range.start <= offset && node_range.end >= offset {
 8465                // If it contains offset, check for task
 8466                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8467                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8468                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8469                }
 8470            }
 8471
 8472            if !cursor.goto_parent() {
 8473                break;
 8474            }
 8475        }
 8476        None
 8477    }
 8478
 8479    fn render_run_indicator(
 8480        &self,
 8481        _style: &EditorStyle,
 8482        is_active: bool,
 8483        row: DisplayRow,
 8484        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8485        cx: &mut Context<Self>,
 8486    ) -> IconButton {
 8487        let color = Color::Muted;
 8488        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8489
 8490        IconButton::new(
 8491            ("run_indicator", row.0 as usize),
 8492            ui::IconName::PlayOutlined,
 8493        )
 8494        .shape(ui::IconButtonShape::Square)
 8495        .icon_size(IconSize::XSmall)
 8496        .icon_color(color)
 8497        .toggle_state(is_active)
 8498        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8499            let quick_launch = match e {
 8500                ClickEvent::Keyboard(_) => true,
 8501                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8502            };
 8503
 8504            window.focus(&editor.focus_handle(cx));
 8505            editor.toggle_code_actions(
 8506                &ToggleCodeActions {
 8507                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8508                    quick_launch,
 8509                },
 8510                window,
 8511                cx,
 8512            );
 8513        }))
 8514        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8515            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8516        }))
 8517    }
 8518
 8519    pub fn context_menu_visible(&self) -> bool {
 8520        !self.edit_prediction_preview_is_active()
 8521            && self
 8522                .context_menu
 8523                .borrow()
 8524                .as_ref()
 8525                .is_some_and(|menu| menu.visible())
 8526    }
 8527
 8528    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8529        self.context_menu
 8530            .borrow()
 8531            .as_ref()
 8532            .map(|menu| menu.origin())
 8533    }
 8534
 8535    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8536        self.context_menu_options = Some(options);
 8537    }
 8538
 8539    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8540    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8541
 8542    fn render_edit_prediction_popover(
 8543        &mut self,
 8544        text_bounds: &Bounds<Pixels>,
 8545        content_origin: gpui::Point<Pixels>,
 8546        right_margin: Pixels,
 8547        editor_snapshot: &EditorSnapshot,
 8548        visible_row_range: Range<DisplayRow>,
 8549        scroll_top: f32,
 8550        scroll_bottom: f32,
 8551        line_layouts: &[LineWithInvisibles],
 8552        line_height: Pixels,
 8553        scroll_pixel_position: gpui::Point<Pixels>,
 8554        newest_selection_head: Option<DisplayPoint>,
 8555        editor_width: Pixels,
 8556        style: &EditorStyle,
 8557        window: &mut Window,
 8558        cx: &mut App,
 8559    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8560        if self.mode().is_minimap() {
 8561            return None;
 8562        }
 8563        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8564
 8565        if self.edit_prediction_visible_in_cursor_popover(true) {
 8566            return None;
 8567        }
 8568
 8569        match &active_edit_prediction.completion {
 8570            EditPrediction::Move { target, .. } => {
 8571                let target_display_point = target.to_display_point(editor_snapshot);
 8572
 8573                if self.edit_prediction_requires_modifier() {
 8574                    if !self.edit_prediction_preview_is_active() {
 8575                        return None;
 8576                    }
 8577
 8578                    self.render_edit_prediction_modifier_jump_popover(
 8579                        text_bounds,
 8580                        content_origin,
 8581                        visible_row_range,
 8582                        line_layouts,
 8583                        line_height,
 8584                        scroll_pixel_position,
 8585                        newest_selection_head,
 8586                        target_display_point,
 8587                        window,
 8588                        cx,
 8589                    )
 8590                } else {
 8591                    self.render_edit_prediction_eager_jump_popover(
 8592                        text_bounds,
 8593                        content_origin,
 8594                        editor_snapshot,
 8595                        visible_row_range,
 8596                        scroll_top,
 8597                        scroll_bottom,
 8598                        line_height,
 8599                        scroll_pixel_position,
 8600                        target_display_point,
 8601                        editor_width,
 8602                        window,
 8603                        cx,
 8604                    )
 8605                }
 8606            }
 8607            EditPrediction::Edit {
 8608                display_mode: EditDisplayMode::Inline,
 8609                ..
 8610            } => None,
 8611            EditPrediction::Edit {
 8612                display_mode: EditDisplayMode::TabAccept,
 8613                edits,
 8614                ..
 8615            } => {
 8616                let range = &edits.first()?.0;
 8617                let target_display_point = range.end.to_display_point(editor_snapshot);
 8618
 8619                self.render_edit_prediction_end_of_line_popover(
 8620                    "Accept",
 8621                    editor_snapshot,
 8622                    visible_row_range,
 8623                    target_display_point,
 8624                    line_height,
 8625                    scroll_pixel_position,
 8626                    content_origin,
 8627                    editor_width,
 8628                    window,
 8629                    cx,
 8630                )
 8631            }
 8632            EditPrediction::Edit {
 8633                edits,
 8634                edit_preview,
 8635                display_mode: EditDisplayMode::DiffPopover,
 8636                snapshot,
 8637            } => self.render_edit_prediction_diff_popover(
 8638                text_bounds,
 8639                content_origin,
 8640                right_margin,
 8641                editor_snapshot,
 8642                visible_row_range,
 8643                line_layouts,
 8644                line_height,
 8645                scroll_pixel_position,
 8646                newest_selection_head,
 8647                editor_width,
 8648                style,
 8649                edits,
 8650                edit_preview,
 8651                snapshot,
 8652                window,
 8653                cx,
 8654            ),
 8655        }
 8656    }
 8657
 8658    fn render_edit_prediction_modifier_jump_popover(
 8659        &mut self,
 8660        text_bounds: &Bounds<Pixels>,
 8661        content_origin: gpui::Point<Pixels>,
 8662        visible_row_range: Range<DisplayRow>,
 8663        line_layouts: &[LineWithInvisibles],
 8664        line_height: Pixels,
 8665        scroll_pixel_position: gpui::Point<Pixels>,
 8666        newest_selection_head: Option<DisplayPoint>,
 8667        target_display_point: DisplayPoint,
 8668        window: &mut Window,
 8669        cx: &mut App,
 8670    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8671        let scrolled_content_origin =
 8672            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8673
 8674        const SCROLL_PADDING_Y: Pixels = px(12.);
 8675
 8676        if target_display_point.row() < visible_row_range.start {
 8677            return self.render_edit_prediction_scroll_popover(
 8678                |_| SCROLL_PADDING_Y,
 8679                IconName::ArrowUp,
 8680                visible_row_range,
 8681                line_layouts,
 8682                newest_selection_head,
 8683                scrolled_content_origin,
 8684                window,
 8685                cx,
 8686            );
 8687        } else if target_display_point.row() >= visible_row_range.end {
 8688            return self.render_edit_prediction_scroll_popover(
 8689                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8690                IconName::ArrowDown,
 8691                visible_row_range,
 8692                line_layouts,
 8693                newest_selection_head,
 8694                scrolled_content_origin,
 8695                window,
 8696                cx,
 8697            );
 8698        }
 8699
 8700        const POLE_WIDTH: Pixels = px(2.);
 8701
 8702        let line_layout =
 8703            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8704        let target_column = target_display_point.column() as usize;
 8705
 8706        let target_x = line_layout.x_for_index(target_column);
 8707        let target_y =
 8708            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8709
 8710        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8711
 8712        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8713        border_color.l += 0.001;
 8714
 8715        let mut element = v_flex()
 8716            .items_end()
 8717            .when(flag_on_right, |el| el.items_start())
 8718            .child(if flag_on_right {
 8719                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8720                    .rounded_bl(px(0.))
 8721                    .rounded_tl(px(0.))
 8722                    .border_l_2()
 8723                    .border_color(border_color)
 8724            } else {
 8725                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8726                    .rounded_br(px(0.))
 8727                    .rounded_tr(px(0.))
 8728                    .border_r_2()
 8729                    .border_color(border_color)
 8730            })
 8731            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8732            .into_any();
 8733
 8734        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8735
 8736        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8737            - point(
 8738                if flag_on_right {
 8739                    POLE_WIDTH
 8740                } else {
 8741                    size.width - POLE_WIDTH
 8742                },
 8743                size.height - line_height,
 8744            );
 8745
 8746        origin.x = origin.x.max(content_origin.x);
 8747
 8748        element.prepaint_at(origin, window, cx);
 8749
 8750        Some((element, origin))
 8751    }
 8752
 8753    fn render_edit_prediction_scroll_popover(
 8754        &mut self,
 8755        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8756        scroll_icon: IconName,
 8757        visible_row_range: Range<DisplayRow>,
 8758        line_layouts: &[LineWithInvisibles],
 8759        newest_selection_head: Option<DisplayPoint>,
 8760        scrolled_content_origin: gpui::Point<Pixels>,
 8761        window: &mut Window,
 8762        cx: &mut App,
 8763    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8764        let mut element = self
 8765            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8766            .into_any();
 8767
 8768        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8769
 8770        let cursor = newest_selection_head?;
 8771        let cursor_row_layout =
 8772            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8773        let cursor_column = cursor.column() as usize;
 8774
 8775        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8776
 8777        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8778
 8779        element.prepaint_at(origin, window, cx);
 8780        Some((element, origin))
 8781    }
 8782
 8783    fn render_edit_prediction_eager_jump_popover(
 8784        &mut self,
 8785        text_bounds: &Bounds<Pixels>,
 8786        content_origin: gpui::Point<Pixels>,
 8787        editor_snapshot: &EditorSnapshot,
 8788        visible_row_range: Range<DisplayRow>,
 8789        scroll_top: f32,
 8790        scroll_bottom: f32,
 8791        line_height: Pixels,
 8792        scroll_pixel_position: gpui::Point<Pixels>,
 8793        target_display_point: DisplayPoint,
 8794        editor_width: Pixels,
 8795        window: &mut Window,
 8796        cx: &mut App,
 8797    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8798        if target_display_point.row().as_f32() < scroll_top {
 8799            let mut element = self
 8800                .render_edit_prediction_line_popover(
 8801                    "Jump to Edit",
 8802                    Some(IconName::ArrowUp),
 8803                    window,
 8804                    cx,
 8805                )?
 8806                .into_any();
 8807
 8808            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8809            let offset = point(
 8810                (text_bounds.size.width - size.width) / 2.,
 8811                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8812            );
 8813
 8814            let origin = text_bounds.origin + offset;
 8815            element.prepaint_at(origin, window, cx);
 8816            Some((element, origin))
 8817        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8818            let mut element = self
 8819                .render_edit_prediction_line_popover(
 8820                    "Jump to Edit",
 8821                    Some(IconName::ArrowDown),
 8822                    window,
 8823                    cx,
 8824                )?
 8825                .into_any();
 8826
 8827            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8828            let offset = point(
 8829                (text_bounds.size.width - size.width) / 2.,
 8830                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8831            );
 8832
 8833            let origin = text_bounds.origin + offset;
 8834            element.prepaint_at(origin, window, cx);
 8835            Some((element, origin))
 8836        } else {
 8837            self.render_edit_prediction_end_of_line_popover(
 8838                "Jump to Edit",
 8839                editor_snapshot,
 8840                visible_row_range,
 8841                target_display_point,
 8842                line_height,
 8843                scroll_pixel_position,
 8844                content_origin,
 8845                editor_width,
 8846                window,
 8847                cx,
 8848            )
 8849        }
 8850    }
 8851
 8852    fn render_edit_prediction_end_of_line_popover(
 8853        self: &mut Editor,
 8854        label: &'static str,
 8855        editor_snapshot: &EditorSnapshot,
 8856        visible_row_range: Range<DisplayRow>,
 8857        target_display_point: DisplayPoint,
 8858        line_height: Pixels,
 8859        scroll_pixel_position: gpui::Point<Pixels>,
 8860        content_origin: gpui::Point<Pixels>,
 8861        editor_width: Pixels,
 8862        window: &mut Window,
 8863        cx: &mut App,
 8864    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8865        let target_line_end = DisplayPoint::new(
 8866            target_display_point.row(),
 8867            editor_snapshot.line_len(target_display_point.row()),
 8868        );
 8869
 8870        let mut element = self
 8871            .render_edit_prediction_line_popover(label, None, window, cx)?
 8872            .into_any();
 8873
 8874        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8875
 8876        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8877
 8878        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8879        let mut origin = start_point
 8880            + line_origin
 8881            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8882        origin.x = origin.x.max(content_origin.x);
 8883
 8884        let max_x = content_origin.x + editor_width - size.width;
 8885
 8886        if origin.x > max_x {
 8887            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8888
 8889            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8890                origin.y += offset;
 8891                IconName::ArrowUp
 8892            } else {
 8893                origin.y -= offset;
 8894                IconName::ArrowDown
 8895            };
 8896
 8897            element = self
 8898                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8899                .into_any();
 8900
 8901            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8902
 8903            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8904        }
 8905
 8906        element.prepaint_at(origin, window, cx);
 8907        Some((element, origin))
 8908    }
 8909
 8910    fn render_edit_prediction_diff_popover(
 8911        self: &Editor,
 8912        text_bounds: &Bounds<Pixels>,
 8913        content_origin: gpui::Point<Pixels>,
 8914        right_margin: Pixels,
 8915        editor_snapshot: &EditorSnapshot,
 8916        visible_row_range: Range<DisplayRow>,
 8917        line_layouts: &[LineWithInvisibles],
 8918        line_height: Pixels,
 8919        scroll_pixel_position: gpui::Point<Pixels>,
 8920        newest_selection_head: Option<DisplayPoint>,
 8921        editor_width: Pixels,
 8922        style: &EditorStyle,
 8923        edits: &Vec<(Range<Anchor>, String)>,
 8924        edit_preview: &Option<language::EditPreview>,
 8925        snapshot: &language::BufferSnapshot,
 8926        window: &mut Window,
 8927        cx: &mut App,
 8928    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8929        let edit_start = edits
 8930            .first()
 8931            .unwrap()
 8932            .0
 8933            .start
 8934            .to_display_point(editor_snapshot);
 8935        let edit_end = edits
 8936            .last()
 8937            .unwrap()
 8938            .0
 8939            .end
 8940            .to_display_point(editor_snapshot);
 8941
 8942        let is_visible = visible_row_range.contains(&edit_start.row())
 8943            || visible_row_range.contains(&edit_end.row());
 8944        if !is_visible {
 8945            return None;
 8946        }
 8947
 8948        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8949            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8950        } else {
 8951            // Fallback for providers without edit_preview
 8952            crate::edit_prediction_fallback_text(edits, cx)
 8953        };
 8954
 8955        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8956        let line_count = highlighted_edits.text.lines().count();
 8957
 8958        const BORDER_WIDTH: Pixels = px(1.);
 8959
 8960        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8961        let has_keybind = keybind.is_some();
 8962
 8963        let mut element = h_flex()
 8964            .items_start()
 8965            .child(
 8966                h_flex()
 8967                    .bg(cx.theme().colors().editor_background)
 8968                    .border(BORDER_WIDTH)
 8969                    .shadow_xs()
 8970                    .border_color(cx.theme().colors().border)
 8971                    .rounded_l_lg()
 8972                    .when(line_count > 1, |el| el.rounded_br_lg())
 8973                    .pr_1()
 8974                    .child(styled_text),
 8975            )
 8976            .child(
 8977                h_flex()
 8978                    .h(line_height + BORDER_WIDTH * 2.)
 8979                    .px_1p5()
 8980                    .gap_1()
 8981                    // Workaround: For some reason, there's a gap if we don't do this
 8982                    .ml(-BORDER_WIDTH)
 8983                    .shadow(vec![gpui::BoxShadow {
 8984                        color: gpui::black().opacity(0.05),
 8985                        offset: point(px(1.), px(1.)),
 8986                        blur_radius: px(2.),
 8987                        spread_radius: px(0.),
 8988                    }])
 8989                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8990                    .border(BORDER_WIDTH)
 8991                    .border_color(cx.theme().colors().border)
 8992                    .rounded_r_lg()
 8993                    .id("edit_prediction_diff_popover_keybind")
 8994                    .when(!has_keybind, |el| {
 8995                        let status_colors = cx.theme().status();
 8996
 8997                        el.bg(status_colors.error_background)
 8998                            .border_color(status_colors.error.opacity(0.6))
 8999                            .child(Icon::new(IconName::Info).color(Color::Error))
 9000                            .cursor_default()
 9001                            .hoverable_tooltip(move |_window, cx| {
 9002                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9003                            })
 9004                    })
 9005                    .children(keybind),
 9006            )
 9007            .into_any();
 9008
 9009        let longest_row =
 9010            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9011        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9012            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9013        } else {
 9014            layout_line(
 9015                longest_row,
 9016                editor_snapshot,
 9017                style,
 9018                editor_width,
 9019                |_| false,
 9020                window,
 9021                cx,
 9022            )
 9023            .width
 9024        };
 9025
 9026        let viewport_bounds =
 9027            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9028                right: -right_margin,
 9029                ..Default::default()
 9030            });
 9031
 9032        let x_after_longest =
 9033            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9034                - scroll_pixel_position.x;
 9035
 9036        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9037
 9038        // Fully visible if it can be displayed within the window (allow overlapping other
 9039        // panes). However, this is only allowed if the popover starts within text_bounds.
 9040        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9041            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9042
 9043        let mut origin = if can_position_to_the_right {
 9044            point(
 9045                x_after_longest,
 9046                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9047                    - scroll_pixel_position.y,
 9048            )
 9049        } else {
 9050            let cursor_row = newest_selection_head.map(|head| head.row());
 9051            let above_edit = edit_start
 9052                .row()
 9053                .0
 9054                .checked_sub(line_count as u32)
 9055                .map(DisplayRow);
 9056            let below_edit = Some(edit_end.row() + 1);
 9057            let above_cursor =
 9058                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9059            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9060
 9061            // Place the edit popover adjacent to the edit if there is a location
 9062            // available that is onscreen and does not obscure the cursor. Otherwise,
 9063            // place it adjacent to the cursor.
 9064            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9065                .into_iter()
 9066                .flatten()
 9067                .find(|&start_row| {
 9068                    let end_row = start_row + line_count as u32;
 9069                    visible_row_range.contains(&start_row)
 9070                        && visible_row_range.contains(&end_row)
 9071                        && cursor_row
 9072                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9073                })?;
 9074
 9075            content_origin
 9076                + point(
 9077                    -scroll_pixel_position.x,
 9078                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9079                )
 9080        };
 9081
 9082        origin.x -= BORDER_WIDTH;
 9083
 9084        window.defer_draw(element, origin, 1);
 9085
 9086        // Do not return an element, since it will already be drawn due to defer_draw.
 9087        None
 9088    }
 9089
 9090    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9091        px(30.)
 9092    }
 9093
 9094    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9095        if self.read_only(cx) {
 9096            cx.theme().players().read_only()
 9097        } else {
 9098            self.style.as_ref().unwrap().local_player
 9099        }
 9100    }
 9101
 9102    fn render_edit_prediction_accept_keybind(
 9103        &self,
 9104        window: &mut Window,
 9105        cx: &App,
 9106    ) -> Option<AnyElement> {
 9107        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9108        let accept_keystroke = accept_binding.keystroke()?;
 9109
 9110        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9111
 9112        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9113            Color::Accent
 9114        } else {
 9115            Color::Muted
 9116        };
 9117
 9118        h_flex()
 9119            .px_0p5()
 9120            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9121            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9122            .text_size(TextSize::XSmall.rems(cx))
 9123            .child(h_flex().children(ui::render_modifiers(
 9124                accept_keystroke.modifiers(),
 9125                PlatformStyle::platform(),
 9126                Some(modifiers_color),
 9127                Some(IconSize::XSmall.rems().into()),
 9128                true,
 9129            )))
 9130            .when(is_platform_style_mac, |parent| {
 9131                parent.child(accept_keystroke.key().to_string())
 9132            })
 9133            .when(!is_platform_style_mac, |parent| {
 9134                parent.child(
 9135                    Key::new(
 9136                        util::capitalize(accept_keystroke.key()),
 9137                        Some(Color::Default),
 9138                    )
 9139                    .size(Some(IconSize::XSmall.rems().into())),
 9140                )
 9141            })
 9142            .into_any()
 9143            .into()
 9144    }
 9145
 9146    fn render_edit_prediction_line_popover(
 9147        &self,
 9148        label: impl Into<SharedString>,
 9149        icon: Option<IconName>,
 9150        window: &mut Window,
 9151        cx: &App,
 9152    ) -> Option<Stateful<Div>> {
 9153        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9154
 9155        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9156        let has_keybind = keybind.is_some();
 9157
 9158        let result = h_flex()
 9159            .id("ep-line-popover")
 9160            .py_0p5()
 9161            .pl_1()
 9162            .pr(padding_right)
 9163            .gap_1()
 9164            .rounded_md()
 9165            .border_1()
 9166            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9167            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9168            .shadow_xs()
 9169            .when(!has_keybind, |el| {
 9170                let status_colors = cx.theme().status();
 9171
 9172                el.bg(status_colors.error_background)
 9173                    .border_color(status_colors.error.opacity(0.6))
 9174                    .pl_2()
 9175                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9176                    .cursor_default()
 9177                    .hoverable_tooltip(move |_window, cx| {
 9178                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9179                    })
 9180            })
 9181            .children(keybind)
 9182            .child(
 9183                Label::new(label)
 9184                    .size(LabelSize::Small)
 9185                    .when(!has_keybind, |el| {
 9186                        el.color(cx.theme().status().error.into()).strikethrough()
 9187                    }),
 9188            )
 9189            .when(!has_keybind, |el| {
 9190                el.child(
 9191                    h_flex().ml_1().child(
 9192                        Icon::new(IconName::Info)
 9193                            .size(IconSize::Small)
 9194                            .color(cx.theme().status().error.into()),
 9195                    ),
 9196                )
 9197            })
 9198            .when_some(icon, |element, icon| {
 9199                element.child(
 9200                    div()
 9201                        .mt(px(1.5))
 9202                        .child(Icon::new(icon).size(IconSize::Small)),
 9203                )
 9204            });
 9205
 9206        Some(result)
 9207    }
 9208
 9209    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9210        let accent_color = cx.theme().colors().text_accent;
 9211        let editor_bg_color = cx.theme().colors().editor_background;
 9212        editor_bg_color.blend(accent_color.opacity(0.1))
 9213    }
 9214
 9215    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9216        let accent_color = cx.theme().colors().text_accent;
 9217        let editor_bg_color = cx.theme().colors().editor_background;
 9218        editor_bg_color.blend(accent_color.opacity(0.6))
 9219    }
 9220    fn get_prediction_provider_icon_name(
 9221        provider: &Option<RegisteredEditPredictionProvider>,
 9222    ) -> IconName {
 9223        match provider {
 9224            Some(provider) => match provider.provider.name() {
 9225                "copilot" => IconName::Copilot,
 9226                "supermaven" => IconName::Supermaven,
 9227                _ => IconName::ZedPredict,
 9228            },
 9229            None => IconName::ZedPredict,
 9230        }
 9231    }
 9232
 9233    fn render_edit_prediction_cursor_popover(
 9234        &self,
 9235        min_width: Pixels,
 9236        max_width: Pixels,
 9237        cursor_point: Point,
 9238        style: &EditorStyle,
 9239        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9240        _window: &Window,
 9241        cx: &mut Context<Editor>,
 9242    ) -> Option<AnyElement> {
 9243        let provider = self.edit_prediction_provider.as_ref()?;
 9244        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9245
 9246        let is_refreshing = provider.provider.is_refreshing(cx);
 9247
 9248        fn pending_completion_container(icon: IconName) -> Div {
 9249            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9250        }
 9251
 9252        let completion = match &self.active_edit_prediction {
 9253            Some(prediction) => {
 9254                if !self.has_visible_completions_menu() {
 9255                    const RADIUS: Pixels = px(6.);
 9256                    const BORDER_WIDTH: Pixels = px(1.);
 9257
 9258                    return Some(
 9259                        h_flex()
 9260                            .elevation_2(cx)
 9261                            .border(BORDER_WIDTH)
 9262                            .border_color(cx.theme().colors().border)
 9263                            .when(accept_keystroke.is_none(), |el| {
 9264                                el.border_color(cx.theme().status().error)
 9265                            })
 9266                            .rounded(RADIUS)
 9267                            .rounded_tl(px(0.))
 9268                            .overflow_hidden()
 9269                            .child(div().px_1p5().child(match &prediction.completion {
 9270                                EditPrediction::Move { target, snapshot } => {
 9271                                    use text::ToPoint as _;
 9272                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9273                                    {
 9274                                        Icon::new(IconName::ZedPredictDown)
 9275                                    } else {
 9276                                        Icon::new(IconName::ZedPredictUp)
 9277                                    }
 9278                                }
 9279                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9280                            }))
 9281                            .child(
 9282                                h_flex()
 9283                                    .gap_1()
 9284                                    .py_1()
 9285                                    .px_2()
 9286                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9287                                    .border_l_1()
 9288                                    .border_color(cx.theme().colors().border)
 9289                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9290                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9291                                        el.child(
 9292                                            Label::new("Hold")
 9293                                                .size(LabelSize::Small)
 9294                                                .when(accept_keystroke.is_none(), |el| {
 9295                                                    el.strikethrough()
 9296                                                })
 9297                                                .line_height_style(LineHeightStyle::UiLabel),
 9298                                        )
 9299                                    })
 9300                                    .id("edit_prediction_cursor_popover_keybind")
 9301                                    .when(accept_keystroke.is_none(), |el| {
 9302                                        let status_colors = cx.theme().status();
 9303
 9304                                        el.bg(status_colors.error_background)
 9305                                            .border_color(status_colors.error.opacity(0.6))
 9306                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9307                                            .cursor_default()
 9308                                            .hoverable_tooltip(move |_window, cx| {
 9309                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9310                                                    .into()
 9311                                            })
 9312                                    })
 9313                                    .when_some(
 9314                                        accept_keystroke.as_ref(),
 9315                                        |el, accept_keystroke| {
 9316                                            el.child(h_flex().children(ui::render_modifiers(
 9317                                                accept_keystroke.modifiers(),
 9318                                                PlatformStyle::platform(),
 9319                                                Some(Color::Default),
 9320                                                Some(IconSize::XSmall.rems().into()),
 9321                                                false,
 9322                                            )))
 9323                                        },
 9324                                    ),
 9325                            )
 9326                            .into_any(),
 9327                    );
 9328                }
 9329
 9330                self.render_edit_prediction_cursor_popover_preview(
 9331                    prediction,
 9332                    cursor_point,
 9333                    style,
 9334                    cx,
 9335                )?
 9336            }
 9337
 9338            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9339                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9340                    stale_completion,
 9341                    cursor_point,
 9342                    style,
 9343                    cx,
 9344                )?,
 9345
 9346                None => pending_completion_container(provider_icon)
 9347                    .child(Label::new("...").size(LabelSize::Small)),
 9348            },
 9349
 9350            None => pending_completion_container(provider_icon)
 9351                .child(Label::new("...").size(LabelSize::Small)),
 9352        };
 9353
 9354        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9355            completion
 9356                .with_animation(
 9357                    "loading-completion",
 9358                    Animation::new(Duration::from_secs(2))
 9359                        .repeat()
 9360                        .with_easing(pulsating_between(0.4, 0.8)),
 9361                    |label, delta| label.opacity(delta),
 9362                )
 9363                .into_any_element()
 9364        } else {
 9365            completion.into_any_element()
 9366        };
 9367
 9368        let has_completion = self.active_edit_prediction.is_some();
 9369
 9370        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9371        Some(
 9372            h_flex()
 9373                .min_w(min_width)
 9374                .max_w(max_width)
 9375                .flex_1()
 9376                .elevation_2(cx)
 9377                .border_color(cx.theme().colors().border)
 9378                .child(
 9379                    div()
 9380                        .flex_1()
 9381                        .py_1()
 9382                        .px_2()
 9383                        .overflow_hidden()
 9384                        .child(completion),
 9385                )
 9386                .when_some(accept_keystroke, |el, accept_keystroke| {
 9387                    if !accept_keystroke.modifiers().modified() {
 9388                        return el;
 9389                    }
 9390
 9391                    el.child(
 9392                        h_flex()
 9393                            .h_full()
 9394                            .border_l_1()
 9395                            .rounded_r_lg()
 9396                            .border_color(cx.theme().colors().border)
 9397                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9398                            .gap_1()
 9399                            .py_1()
 9400                            .px_2()
 9401                            .child(
 9402                                h_flex()
 9403                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9404                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9405                                    .child(h_flex().children(ui::render_modifiers(
 9406                                        accept_keystroke.modifiers(),
 9407                                        PlatformStyle::platform(),
 9408                                        Some(if !has_completion {
 9409                                            Color::Muted
 9410                                        } else {
 9411                                            Color::Default
 9412                                        }),
 9413                                        None,
 9414                                        false,
 9415                                    ))),
 9416                            )
 9417                            .child(Label::new("Preview").into_any_element())
 9418                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9419                    )
 9420                })
 9421                .into_any(),
 9422        )
 9423    }
 9424
 9425    fn render_edit_prediction_cursor_popover_preview(
 9426        &self,
 9427        completion: &EditPredictionState,
 9428        cursor_point: Point,
 9429        style: &EditorStyle,
 9430        cx: &mut Context<Editor>,
 9431    ) -> Option<Div> {
 9432        use text::ToPoint as _;
 9433
 9434        fn render_relative_row_jump(
 9435            prefix: impl Into<String>,
 9436            current_row: u32,
 9437            target_row: u32,
 9438        ) -> Div {
 9439            let (row_diff, arrow) = if target_row < current_row {
 9440                (current_row - target_row, IconName::ArrowUp)
 9441            } else {
 9442                (target_row - current_row, IconName::ArrowDown)
 9443            };
 9444
 9445            h_flex()
 9446                .child(
 9447                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9448                        .color(Color::Muted)
 9449                        .size(LabelSize::Small),
 9450                )
 9451                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9452        }
 9453
 9454        let supports_jump = self
 9455            .edit_prediction_provider
 9456            .as_ref()
 9457            .map(|provider| provider.provider.supports_jump_to_edit())
 9458            .unwrap_or(true);
 9459
 9460        match &completion.completion {
 9461            EditPrediction::Move {
 9462                target, snapshot, ..
 9463            } => {
 9464                if !supports_jump {
 9465                    return None;
 9466                }
 9467
 9468                Some(
 9469                    h_flex()
 9470                        .px_2()
 9471                        .gap_2()
 9472                        .flex_1()
 9473                        .child(
 9474                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9475                                Icon::new(IconName::ZedPredictDown)
 9476                            } else {
 9477                                Icon::new(IconName::ZedPredictUp)
 9478                            },
 9479                        )
 9480                        .child(Label::new("Jump to Edit")),
 9481                )
 9482            }
 9483
 9484            EditPrediction::Edit {
 9485                edits,
 9486                edit_preview,
 9487                snapshot,
 9488                display_mode: _,
 9489            } => {
 9490                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9491
 9492                let (highlighted_edits, has_more_lines) =
 9493                    if let Some(edit_preview) = edit_preview.as_ref() {
 9494                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9495                            .first_line_preview()
 9496                    } else {
 9497                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9498                    };
 9499
 9500                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9501                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9502
 9503                let preview = h_flex()
 9504                    .gap_1()
 9505                    .min_w_16()
 9506                    .child(styled_text)
 9507                    .when(has_more_lines, |parent| parent.child(""));
 9508
 9509                let left = if supports_jump && first_edit_row != cursor_point.row {
 9510                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9511                        .into_any_element()
 9512                } else {
 9513                    let icon_name =
 9514                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9515                    Icon::new(icon_name).into_any_element()
 9516                };
 9517
 9518                Some(
 9519                    h_flex()
 9520                        .h_full()
 9521                        .flex_1()
 9522                        .gap_2()
 9523                        .pr_1()
 9524                        .overflow_x_hidden()
 9525                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9526                        .child(left)
 9527                        .child(preview),
 9528                )
 9529            }
 9530        }
 9531    }
 9532
 9533    pub fn render_context_menu(
 9534        &self,
 9535        style: &EditorStyle,
 9536        max_height_in_lines: u32,
 9537        window: &mut Window,
 9538        cx: &mut Context<Editor>,
 9539    ) -> Option<AnyElement> {
 9540        let menu = self.context_menu.borrow();
 9541        let menu = menu.as_ref()?;
 9542        if !menu.visible() {
 9543            return None;
 9544        };
 9545        Some(menu.render(style, max_height_in_lines, window, cx))
 9546    }
 9547
 9548    fn render_context_menu_aside(
 9549        &mut self,
 9550        max_size: Size<Pixels>,
 9551        window: &mut Window,
 9552        cx: &mut Context<Editor>,
 9553    ) -> Option<AnyElement> {
 9554        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9555            if menu.visible() {
 9556                menu.render_aside(max_size, window, cx)
 9557            } else {
 9558                None
 9559            }
 9560        })
 9561    }
 9562
 9563    fn hide_context_menu(
 9564        &mut self,
 9565        window: &mut Window,
 9566        cx: &mut Context<Self>,
 9567    ) -> Option<CodeContextMenu> {
 9568        cx.notify();
 9569        self.completion_tasks.clear();
 9570        let context_menu = self.context_menu.borrow_mut().take();
 9571        self.stale_edit_prediction_in_menu.take();
 9572        self.update_visible_edit_prediction(window, cx);
 9573        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9574            && let Some(completion_provider) = &self.completion_provider
 9575        {
 9576            completion_provider.selection_changed(None, window, cx);
 9577        }
 9578        context_menu
 9579    }
 9580
 9581    fn show_snippet_choices(
 9582        &mut self,
 9583        choices: &Vec<String>,
 9584        selection: Range<Anchor>,
 9585        cx: &mut Context<Self>,
 9586    ) {
 9587        let Some((_, buffer, _)) = self
 9588            .buffer()
 9589            .read(cx)
 9590            .excerpt_containing(selection.start, cx)
 9591        else {
 9592            return;
 9593        };
 9594        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9595        else {
 9596            return;
 9597        };
 9598        if buffer != end_buffer {
 9599            log::error!("expected anchor range to have matching buffer IDs");
 9600            return;
 9601        }
 9602
 9603        let id = post_inc(&mut self.next_completion_id);
 9604        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9605        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9606            CompletionsMenu::new_snippet_choices(
 9607                id,
 9608                true,
 9609                choices,
 9610                selection,
 9611                buffer,
 9612                snippet_sort_order,
 9613            ),
 9614        ));
 9615    }
 9616
 9617    pub fn insert_snippet(
 9618        &mut self,
 9619        insertion_ranges: &[Range<usize>],
 9620        snippet: Snippet,
 9621        window: &mut Window,
 9622        cx: &mut Context<Self>,
 9623    ) -> Result<()> {
 9624        struct Tabstop<T> {
 9625            is_end_tabstop: bool,
 9626            ranges: Vec<Range<T>>,
 9627            choices: Option<Vec<String>>,
 9628        }
 9629
 9630        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9631            let snippet_text: Arc<str> = snippet.text.clone().into();
 9632            let edits = insertion_ranges
 9633                .iter()
 9634                .cloned()
 9635                .map(|range| (range, snippet_text.clone()));
 9636            let autoindent_mode = AutoindentMode::Block {
 9637                original_indent_columns: Vec::new(),
 9638            };
 9639            buffer.edit(edits, Some(autoindent_mode), cx);
 9640
 9641            let snapshot = &*buffer.read(cx);
 9642            let snippet = &snippet;
 9643            snippet
 9644                .tabstops
 9645                .iter()
 9646                .map(|tabstop| {
 9647                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9648                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9649                    });
 9650                    let mut tabstop_ranges = tabstop
 9651                        .ranges
 9652                        .iter()
 9653                        .flat_map(|tabstop_range| {
 9654                            let mut delta = 0_isize;
 9655                            insertion_ranges.iter().map(move |insertion_range| {
 9656                                let insertion_start = insertion_range.start as isize + delta;
 9657                                delta +=
 9658                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9659
 9660                                let start = ((insertion_start + tabstop_range.start) as usize)
 9661                                    .min(snapshot.len());
 9662                                let end = ((insertion_start + tabstop_range.end) as usize)
 9663                                    .min(snapshot.len());
 9664                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9665                            })
 9666                        })
 9667                        .collect::<Vec<_>>();
 9668                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9669
 9670                    Tabstop {
 9671                        is_end_tabstop,
 9672                        ranges: tabstop_ranges,
 9673                        choices: tabstop.choices.clone(),
 9674                    }
 9675                })
 9676                .collect::<Vec<_>>()
 9677        });
 9678        if let Some(tabstop) = tabstops.first() {
 9679            self.change_selections(Default::default(), window, cx, |s| {
 9680                // Reverse order so that the first range is the newest created selection.
 9681                // Completions will use it and autoscroll will prioritize it.
 9682                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9683            });
 9684
 9685            if let Some(choices) = &tabstop.choices
 9686                && let Some(selection) = tabstop.ranges.first()
 9687            {
 9688                self.show_snippet_choices(choices, selection.clone(), cx)
 9689            }
 9690
 9691            // If we're already at the last tabstop and it's at the end of the snippet,
 9692            // we're done, we don't need to keep the state around.
 9693            if !tabstop.is_end_tabstop {
 9694                let choices = tabstops
 9695                    .iter()
 9696                    .map(|tabstop| tabstop.choices.clone())
 9697                    .collect();
 9698
 9699                let ranges = tabstops
 9700                    .into_iter()
 9701                    .map(|tabstop| tabstop.ranges)
 9702                    .collect::<Vec<_>>();
 9703
 9704                self.snippet_stack.push(SnippetState {
 9705                    active_index: 0,
 9706                    ranges,
 9707                    choices,
 9708                });
 9709            }
 9710
 9711            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9712            if self.autoclose_regions.is_empty() {
 9713                let snapshot = self.buffer.read(cx).snapshot(cx);
 9714                let mut all_selections = self.selections.all::<Point>(cx);
 9715                for selection in &mut all_selections {
 9716                    let selection_head = selection.head();
 9717                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9718                        continue;
 9719                    };
 9720
 9721                    let mut bracket_pair = None;
 9722                    let max_lookup_length = scope
 9723                        .brackets()
 9724                        .map(|(pair, _)| {
 9725                            pair.start
 9726                                .as_str()
 9727                                .chars()
 9728                                .count()
 9729                                .max(pair.end.as_str().chars().count())
 9730                        })
 9731                        .max();
 9732                    if let Some(max_lookup_length) = max_lookup_length {
 9733                        let next_text = snapshot
 9734                            .chars_at(selection_head)
 9735                            .take(max_lookup_length)
 9736                            .collect::<String>();
 9737                        let prev_text = snapshot
 9738                            .reversed_chars_at(selection_head)
 9739                            .take(max_lookup_length)
 9740                            .collect::<String>();
 9741
 9742                        for (pair, enabled) in scope.brackets() {
 9743                            if enabled
 9744                                && pair.close
 9745                                && prev_text.starts_with(pair.start.as_str())
 9746                                && next_text.starts_with(pair.end.as_str())
 9747                            {
 9748                                bracket_pair = Some(pair.clone());
 9749                                break;
 9750                            }
 9751                        }
 9752                    }
 9753
 9754                    if let Some(pair) = bracket_pair {
 9755                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9756                        let autoclose_enabled =
 9757                            self.use_autoclose && snapshot_settings.use_autoclose;
 9758                        if autoclose_enabled {
 9759                            let start = snapshot.anchor_after(selection_head);
 9760                            let end = snapshot.anchor_after(selection_head);
 9761                            self.autoclose_regions.push(AutocloseRegion {
 9762                                selection_id: selection.id,
 9763                                range: start..end,
 9764                                pair,
 9765                            });
 9766                        }
 9767                    }
 9768                }
 9769            }
 9770        }
 9771        Ok(())
 9772    }
 9773
 9774    pub fn move_to_next_snippet_tabstop(
 9775        &mut self,
 9776        window: &mut Window,
 9777        cx: &mut Context<Self>,
 9778    ) -> bool {
 9779        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9780    }
 9781
 9782    pub fn move_to_prev_snippet_tabstop(
 9783        &mut self,
 9784        window: &mut Window,
 9785        cx: &mut Context<Self>,
 9786    ) -> bool {
 9787        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9788    }
 9789
 9790    pub fn move_to_snippet_tabstop(
 9791        &mut self,
 9792        bias: Bias,
 9793        window: &mut Window,
 9794        cx: &mut Context<Self>,
 9795    ) -> bool {
 9796        if let Some(mut snippet) = self.snippet_stack.pop() {
 9797            match bias {
 9798                Bias::Left => {
 9799                    if snippet.active_index > 0 {
 9800                        snippet.active_index -= 1;
 9801                    } else {
 9802                        self.snippet_stack.push(snippet);
 9803                        return false;
 9804                    }
 9805                }
 9806                Bias::Right => {
 9807                    if snippet.active_index + 1 < snippet.ranges.len() {
 9808                        snippet.active_index += 1;
 9809                    } else {
 9810                        self.snippet_stack.push(snippet);
 9811                        return false;
 9812                    }
 9813                }
 9814            }
 9815            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9816                self.change_selections(Default::default(), window, cx, |s| {
 9817                    // Reverse order so that the first range is the newest created selection.
 9818                    // Completions will use it and autoscroll will prioritize it.
 9819                    s.select_ranges(current_ranges.iter().rev().cloned())
 9820                });
 9821
 9822                if let Some(choices) = &snippet.choices[snippet.active_index]
 9823                    && let Some(selection) = current_ranges.first()
 9824                {
 9825                    self.show_snippet_choices(choices, selection.clone(), cx);
 9826                }
 9827
 9828                // If snippet state is not at the last tabstop, push it back on the stack
 9829                if snippet.active_index + 1 < snippet.ranges.len() {
 9830                    self.snippet_stack.push(snippet);
 9831                }
 9832                return true;
 9833            }
 9834        }
 9835
 9836        false
 9837    }
 9838
 9839    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9840        self.transact(window, cx, |this, window, cx| {
 9841            this.select_all(&SelectAll, window, cx);
 9842            this.insert("", window, cx);
 9843        });
 9844    }
 9845
 9846    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9847        if self.read_only(cx) {
 9848            return;
 9849        }
 9850        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9851        self.transact(window, cx, |this, window, cx| {
 9852            this.select_autoclose_pair(window, cx);
 9853            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9854            if !this.linked_edit_ranges.is_empty() {
 9855                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9856                let snapshot = this.buffer.read(cx).snapshot(cx);
 9857
 9858                for selection in selections.iter() {
 9859                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9860                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9861                    if selection_start.buffer_id != selection_end.buffer_id {
 9862                        continue;
 9863                    }
 9864                    if let Some(ranges) =
 9865                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9866                    {
 9867                        for (buffer, entries) in ranges {
 9868                            linked_ranges.entry(buffer).or_default().extend(entries);
 9869                        }
 9870                    }
 9871                }
 9872            }
 9873
 9874            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9875            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9876            for selection in &mut selections {
 9877                if selection.is_empty() {
 9878                    let old_head = selection.head();
 9879                    let mut new_head =
 9880                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9881                            .to_point(&display_map);
 9882                    if let Some((buffer, line_buffer_range)) = display_map
 9883                        .buffer_snapshot
 9884                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9885                    {
 9886                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9887                        let indent_len = match indent_size.kind {
 9888                            IndentKind::Space => {
 9889                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9890                            }
 9891                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9892                        };
 9893                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9894                            let indent_len = indent_len.get();
 9895                            new_head = cmp::min(
 9896                                new_head,
 9897                                MultiBufferPoint::new(
 9898                                    old_head.row,
 9899                                    ((old_head.column - 1) / indent_len) * indent_len,
 9900                                ),
 9901                            );
 9902                        }
 9903                    }
 9904
 9905                    selection.set_head(new_head, SelectionGoal::None);
 9906                }
 9907            }
 9908
 9909            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9910            this.insert("", window, cx);
 9911            let empty_str: Arc<str> = Arc::from("");
 9912            for (buffer, edits) in linked_ranges {
 9913                let snapshot = buffer.read(cx).snapshot();
 9914                use text::ToPoint as TP;
 9915
 9916                let edits = edits
 9917                    .into_iter()
 9918                    .map(|range| {
 9919                        let end_point = TP::to_point(&range.end, &snapshot);
 9920                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9921
 9922                        if end_point == start_point {
 9923                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9924                                .saturating_sub(1);
 9925                            start_point =
 9926                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9927                        };
 9928
 9929                        (start_point..end_point, empty_str.clone())
 9930                    })
 9931                    .sorted_by_key(|(range, _)| range.start)
 9932                    .collect::<Vec<_>>();
 9933                buffer.update(cx, |this, cx| {
 9934                    this.edit(edits, None, cx);
 9935                })
 9936            }
 9937            this.refresh_edit_prediction(true, false, window, cx);
 9938            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9939        });
 9940    }
 9941
 9942    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9943        if self.read_only(cx) {
 9944            return;
 9945        }
 9946        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9947        self.transact(window, cx, |this, window, cx| {
 9948            this.change_selections(Default::default(), window, cx, |s| {
 9949                s.move_with(|map, selection| {
 9950                    if selection.is_empty() {
 9951                        let cursor = movement::right(map, selection.head());
 9952                        selection.end = cursor;
 9953                        selection.reversed = true;
 9954                        selection.goal = SelectionGoal::None;
 9955                    }
 9956                })
 9957            });
 9958            this.insert("", window, cx);
 9959            this.refresh_edit_prediction(true, false, window, cx);
 9960        });
 9961    }
 9962
 9963    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9964        if self.mode.is_single_line() {
 9965            cx.propagate();
 9966            return;
 9967        }
 9968
 9969        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9970        if self.move_to_prev_snippet_tabstop(window, cx) {
 9971            return;
 9972        }
 9973        self.outdent(&Outdent, window, cx);
 9974    }
 9975
 9976    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9977        if self.mode.is_single_line() {
 9978            cx.propagate();
 9979            return;
 9980        }
 9981
 9982        if self.move_to_next_snippet_tabstop(window, cx) {
 9983            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9984            return;
 9985        }
 9986        if self.read_only(cx) {
 9987            return;
 9988        }
 9989        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9990        let mut selections = self.selections.all_adjusted(cx);
 9991        let buffer = self.buffer.read(cx);
 9992        let snapshot = buffer.snapshot(cx);
 9993        let rows_iter = selections.iter().map(|s| s.head().row);
 9994        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9995
 9996        let has_some_cursor_in_whitespace = selections
 9997            .iter()
 9998            .filter(|selection| selection.is_empty())
 9999            .any(|selection| {
10000                let cursor = selection.head();
10001                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10002                cursor.column < current_indent.len
10003            });
10004
10005        let mut edits = Vec::new();
10006        let mut prev_edited_row = 0;
10007        let mut row_delta = 0;
10008        for selection in &mut selections {
10009            if selection.start.row != prev_edited_row {
10010                row_delta = 0;
10011            }
10012            prev_edited_row = selection.end.row;
10013
10014            // If the selection is non-empty, then increase the indentation of the selected lines.
10015            if !selection.is_empty() {
10016                row_delta =
10017                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10018                continue;
10019            }
10020
10021            let cursor = selection.head();
10022            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10023            if let Some(suggested_indent) =
10024                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10025            {
10026                // Don't do anything if already at suggested indent
10027                // and there is any other cursor which is not
10028                if has_some_cursor_in_whitespace
10029                    && cursor.column == current_indent.len
10030                    && current_indent.len == suggested_indent.len
10031                {
10032                    continue;
10033                }
10034
10035                // Adjust line and move cursor to suggested indent
10036                // if cursor is not at suggested indent
10037                if cursor.column < suggested_indent.len
10038                    && cursor.column <= current_indent.len
10039                    && current_indent.len <= suggested_indent.len
10040                {
10041                    selection.start = Point::new(cursor.row, suggested_indent.len);
10042                    selection.end = selection.start;
10043                    if row_delta == 0 {
10044                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10045                            cursor.row,
10046                            current_indent,
10047                            suggested_indent,
10048                        ));
10049                        row_delta = suggested_indent.len - current_indent.len;
10050                    }
10051                    continue;
10052                }
10053
10054                // If current indent is more than suggested indent
10055                // only move cursor to current indent and skip indent
10056                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10057                    selection.start = Point::new(cursor.row, current_indent.len);
10058                    selection.end = selection.start;
10059                    continue;
10060                }
10061            }
10062
10063            // Otherwise, insert a hard or soft tab.
10064            let settings = buffer.language_settings_at(cursor, cx);
10065            let tab_size = if settings.hard_tabs {
10066                IndentSize::tab()
10067            } else {
10068                let tab_size = settings.tab_size.get();
10069                let indent_remainder = snapshot
10070                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10071                    .flat_map(str::chars)
10072                    .fold(row_delta % tab_size, |counter: u32, c| {
10073                        if c == '\t' {
10074                            0
10075                        } else {
10076                            (counter + 1) % tab_size
10077                        }
10078                    });
10079
10080                let chars_to_next_tab_stop = tab_size - indent_remainder;
10081                IndentSize::spaces(chars_to_next_tab_stop)
10082            };
10083            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10084            selection.end = selection.start;
10085            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10086            row_delta += tab_size.len;
10087        }
10088
10089        self.transact(window, cx, |this, window, cx| {
10090            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10091            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10092            this.refresh_edit_prediction(true, false, window, cx);
10093        });
10094    }
10095
10096    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10097        if self.read_only(cx) {
10098            return;
10099        }
10100        if self.mode.is_single_line() {
10101            cx.propagate();
10102            return;
10103        }
10104
10105        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10106        let mut selections = self.selections.all::<Point>(cx);
10107        let mut prev_edited_row = 0;
10108        let mut row_delta = 0;
10109        let mut edits = Vec::new();
10110        let buffer = self.buffer.read(cx);
10111        let snapshot = buffer.snapshot(cx);
10112        for selection in &mut selections {
10113            if selection.start.row != prev_edited_row {
10114                row_delta = 0;
10115            }
10116            prev_edited_row = selection.end.row;
10117
10118            row_delta =
10119                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10120        }
10121
10122        self.transact(window, cx, |this, window, cx| {
10123            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10124            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10125        });
10126    }
10127
10128    fn indent_selection(
10129        buffer: &MultiBuffer,
10130        snapshot: &MultiBufferSnapshot,
10131        selection: &mut Selection<Point>,
10132        edits: &mut Vec<(Range<Point>, String)>,
10133        delta_for_start_row: u32,
10134        cx: &App,
10135    ) -> u32 {
10136        let settings = buffer.language_settings_at(selection.start, cx);
10137        let tab_size = settings.tab_size.get();
10138        let indent_kind = if settings.hard_tabs {
10139            IndentKind::Tab
10140        } else {
10141            IndentKind::Space
10142        };
10143        let mut start_row = selection.start.row;
10144        let mut end_row = selection.end.row + 1;
10145
10146        // If a selection ends at the beginning of a line, don't indent
10147        // that last line.
10148        if selection.end.column == 0 && selection.end.row > selection.start.row {
10149            end_row -= 1;
10150        }
10151
10152        // Avoid re-indenting a row that has already been indented by a
10153        // previous selection, but still update this selection's column
10154        // to reflect that indentation.
10155        if delta_for_start_row > 0 {
10156            start_row += 1;
10157            selection.start.column += delta_for_start_row;
10158            if selection.end.row == selection.start.row {
10159                selection.end.column += delta_for_start_row;
10160            }
10161        }
10162
10163        let mut delta_for_end_row = 0;
10164        let has_multiple_rows = start_row + 1 != end_row;
10165        for row in start_row..end_row {
10166            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10167            let indent_delta = match (current_indent.kind, indent_kind) {
10168                (IndentKind::Space, IndentKind::Space) => {
10169                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10170                    IndentSize::spaces(columns_to_next_tab_stop)
10171                }
10172                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10173                (_, IndentKind::Tab) => IndentSize::tab(),
10174            };
10175
10176            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10177                0
10178            } else {
10179                selection.start.column
10180            };
10181            let row_start = Point::new(row, start);
10182            edits.push((
10183                row_start..row_start,
10184                indent_delta.chars().collect::<String>(),
10185            ));
10186
10187            // Update this selection's endpoints to reflect the indentation.
10188            if row == selection.start.row {
10189                selection.start.column += indent_delta.len;
10190            }
10191            if row == selection.end.row {
10192                selection.end.column += indent_delta.len;
10193                delta_for_end_row = indent_delta.len;
10194            }
10195        }
10196
10197        if selection.start.row == selection.end.row {
10198            delta_for_start_row + delta_for_end_row
10199        } else {
10200            delta_for_end_row
10201        }
10202    }
10203
10204    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10205        if self.read_only(cx) {
10206            return;
10207        }
10208        if self.mode.is_single_line() {
10209            cx.propagate();
10210            return;
10211        }
10212
10213        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10214        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10215        let selections = self.selections.all::<Point>(cx);
10216        let mut deletion_ranges = Vec::new();
10217        let mut last_outdent = None;
10218        {
10219            let buffer = self.buffer.read(cx);
10220            let snapshot = buffer.snapshot(cx);
10221            for selection in &selections {
10222                let settings = buffer.language_settings_at(selection.start, cx);
10223                let tab_size = settings.tab_size.get();
10224                let mut rows = selection.spanned_rows(false, &display_map);
10225
10226                // Avoid re-outdenting a row that has already been outdented by a
10227                // previous selection.
10228                if let Some(last_row) = last_outdent
10229                    && last_row == rows.start
10230                {
10231                    rows.start = rows.start.next_row();
10232                }
10233                let has_multiple_rows = rows.len() > 1;
10234                for row in rows.iter_rows() {
10235                    let indent_size = snapshot.indent_size_for_line(row);
10236                    if indent_size.len > 0 {
10237                        let deletion_len = match indent_size.kind {
10238                            IndentKind::Space => {
10239                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10240                                if columns_to_prev_tab_stop == 0 {
10241                                    tab_size
10242                                } else {
10243                                    columns_to_prev_tab_stop
10244                                }
10245                            }
10246                            IndentKind::Tab => 1,
10247                        };
10248                        let start = if has_multiple_rows
10249                            || deletion_len > selection.start.column
10250                            || indent_size.len < selection.start.column
10251                        {
10252                            0
10253                        } else {
10254                            selection.start.column - deletion_len
10255                        };
10256                        deletion_ranges.push(
10257                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10258                        );
10259                        last_outdent = Some(row);
10260                    }
10261                }
10262            }
10263        }
10264
10265        self.transact(window, cx, |this, window, cx| {
10266            this.buffer.update(cx, |buffer, cx| {
10267                let empty_str: Arc<str> = Arc::default();
10268                buffer.edit(
10269                    deletion_ranges
10270                        .into_iter()
10271                        .map(|range| (range, empty_str.clone())),
10272                    None,
10273                    cx,
10274                );
10275            });
10276            let selections = this.selections.all::<usize>(cx);
10277            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10278        });
10279    }
10280
10281    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10282        if self.read_only(cx) {
10283            return;
10284        }
10285        if self.mode.is_single_line() {
10286            cx.propagate();
10287            return;
10288        }
10289
10290        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10291        let selections = self
10292            .selections
10293            .all::<usize>(cx)
10294            .into_iter()
10295            .map(|s| s.range());
10296
10297        self.transact(window, cx, |this, window, cx| {
10298            this.buffer.update(cx, |buffer, cx| {
10299                buffer.autoindent_ranges(selections, cx);
10300            });
10301            let selections = this.selections.all::<usize>(cx);
10302            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10303        });
10304    }
10305
10306    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10307        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10308        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10309        let selections = self.selections.all::<Point>(cx);
10310
10311        let mut new_cursors = Vec::new();
10312        let mut edit_ranges = Vec::new();
10313        let mut selections = selections.iter().peekable();
10314        while let Some(selection) = selections.next() {
10315            let mut rows = selection.spanned_rows(false, &display_map);
10316            let goal_display_column = selection.head().to_display_point(&display_map).column();
10317
10318            // Accumulate contiguous regions of rows that we want to delete.
10319            while let Some(next_selection) = selections.peek() {
10320                let next_rows = next_selection.spanned_rows(false, &display_map);
10321                if next_rows.start <= rows.end {
10322                    rows.end = next_rows.end;
10323                    selections.next().unwrap();
10324                } else {
10325                    break;
10326                }
10327            }
10328
10329            let buffer = &display_map.buffer_snapshot;
10330            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10331            let edit_end;
10332            let cursor_buffer_row;
10333            if buffer.max_point().row >= rows.end.0 {
10334                // If there's a line after the range, delete the \n from the end of the row range
10335                // and position the cursor on the next line.
10336                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10337                cursor_buffer_row = rows.end;
10338            } else {
10339                // If there isn't a line after the range, delete the \n from the line before the
10340                // start of the row range and position the cursor there.
10341                edit_start = edit_start.saturating_sub(1);
10342                edit_end = buffer.len();
10343                cursor_buffer_row = rows.start.previous_row();
10344            }
10345
10346            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10347            *cursor.column_mut() =
10348                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10349
10350            new_cursors.push((
10351                selection.id,
10352                buffer.anchor_after(cursor.to_point(&display_map)),
10353            ));
10354            edit_ranges.push(edit_start..edit_end);
10355        }
10356
10357        self.transact(window, cx, |this, window, cx| {
10358            let buffer = this.buffer.update(cx, |buffer, cx| {
10359                let empty_str: Arc<str> = Arc::default();
10360                buffer.edit(
10361                    edit_ranges
10362                        .into_iter()
10363                        .map(|range| (range, empty_str.clone())),
10364                    None,
10365                    cx,
10366                );
10367                buffer.snapshot(cx)
10368            });
10369            let new_selections = new_cursors
10370                .into_iter()
10371                .map(|(id, cursor)| {
10372                    let cursor = cursor.to_point(&buffer);
10373                    Selection {
10374                        id,
10375                        start: cursor,
10376                        end: cursor,
10377                        reversed: false,
10378                        goal: SelectionGoal::None,
10379                    }
10380                })
10381                .collect();
10382
10383            this.change_selections(Default::default(), window, cx, |s| {
10384                s.select(new_selections);
10385            });
10386        });
10387    }
10388
10389    pub fn join_lines_impl(
10390        &mut self,
10391        insert_whitespace: bool,
10392        window: &mut Window,
10393        cx: &mut Context<Self>,
10394    ) {
10395        if self.read_only(cx) {
10396            return;
10397        }
10398        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10399        for selection in self.selections.all::<Point>(cx) {
10400            let start = MultiBufferRow(selection.start.row);
10401            // Treat single line selections as if they include the next line. Otherwise this action
10402            // would do nothing for single line selections individual cursors.
10403            let end = if selection.start.row == selection.end.row {
10404                MultiBufferRow(selection.start.row + 1)
10405            } else {
10406                MultiBufferRow(selection.end.row)
10407            };
10408
10409            if let Some(last_row_range) = row_ranges.last_mut()
10410                && start <= last_row_range.end
10411            {
10412                last_row_range.end = end;
10413                continue;
10414            }
10415            row_ranges.push(start..end);
10416        }
10417
10418        let snapshot = self.buffer.read(cx).snapshot(cx);
10419        let mut cursor_positions = Vec::new();
10420        for row_range in &row_ranges {
10421            let anchor = snapshot.anchor_before(Point::new(
10422                row_range.end.previous_row().0,
10423                snapshot.line_len(row_range.end.previous_row()),
10424            ));
10425            cursor_positions.push(anchor..anchor);
10426        }
10427
10428        self.transact(window, cx, |this, window, cx| {
10429            for row_range in row_ranges.into_iter().rev() {
10430                for row in row_range.iter_rows().rev() {
10431                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10432                    let next_line_row = row.next_row();
10433                    let indent = snapshot.indent_size_for_line(next_line_row);
10434                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10435
10436                    let replace =
10437                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10438                            " "
10439                        } else {
10440                            ""
10441                        };
10442
10443                    this.buffer.update(cx, |buffer, cx| {
10444                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10445                    });
10446                }
10447            }
10448
10449            this.change_selections(Default::default(), window, cx, |s| {
10450                s.select_anchor_ranges(cursor_positions)
10451            });
10452        });
10453    }
10454
10455    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10456        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10457        self.join_lines_impl(true, window, cx);
10458    }
10459
10460    pub fn sort_lines_case_sensitive(
10461        &mut self,
10462        _: &SortLinesCaseSensitive,
10463        window: &mut Window,
10464        cx: &mut Context<Self>,
10465    ) {
10466        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10467    }
10468
10469    pub fn sort_lines_by_length(
10470        &mut self,
10471        _: &SortLinesByLength,
10472        window: &mut Window,
10473        cx: &mut Context<Self>,
10474    ) {
10475        self.manipulate_immutable_lines(window, cx, |lines| {
10476            lines.sort_by_key(|&line| line.chars().count())
10477        })
10478    }
10479
10480    pub fn sort_lines_case_insensitive(
10481        &mut self,
10482        _: &SortLinesCaseInsensitive,
10483        window: &mut Window,
10484        cx: &mut Context<Self>,
10485    ) {
10486        self.manipulate_immutable_lines(window, cx, |lines| {
10487            lines.sort_by_key(|line| line.to_lowercase())
10488        })
10489    }
10490
10491    pub fn unique_lines_case_insensitive(
10492        &mut self,
10493        _: &UniqueLinesCaseInsensitive,
10494        window: &mut Window,
10495        cx: &mut Context<Self>,
10496    ) {
10497        self.manipulate_immutable_lines(window, cx, |lines| {
10498            let mut seen = HashSet::default();
10499            lines.retain(|line| seen.insert(line.to_lowercase()));
10500        })
10501    }
10502
10503    pub fn unique_lines_case_sensitive(
10504        &mut self,
10505        _: &UniqueLinesCaseSensitive,
10506        window: &mut Window,
10507        cx: &mut Context<Self>,
10508    ) {
10509        self.manipulate_immutable_lines(window, cx, |lines| {
10510            let mut seen = HashSet::default();
10511            lines.retain(|line| seen.insert(*line));
10512        })
10513    }
10514
10515    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10516        let snapshot = self.buffer.read(cx).snapshot(cx);
10517        for selection in self.selections.disjoint_anchors_arc().iter() {
10518            if snapshot
10519                .language_at(selection.start)
10520                .and_then(|lang| lang.config().wrap_characters.as_ref())
10521                .is_some()
10522            {
10523                return true;
10524            }
10525        }
10526        false
10527    }
10528
10529    fn wrap_selections_in_tag(
10530        &mut self,
10531        _: &WrapSelectionsInTag,
10532        window: &mut Window,
10533        cx: &mut Context<Self>,
10534    ) {
10535        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10536
10537        let snapshot = self.buffer.read(cx).snapshot(cx);
10538
10539        let mut edits = Vec::new();
10540        let mut boundaries = Vec::new();
10541
10542        for selection in self.selections.all::<Point>(cx).iter() {
10543            let Some(wrap_config) = snapshot
10544                .language_at(selection.start)
10545                .and_then(|lang| lang.config().wrap_characters.clone())
10546            else {
10547                continue;
10548            };
10549
10550            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10551            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10552
10553            let start_before = snapshot.anchor_before(selection.start);
10554            let end_after = snapshot.anchor_after(selection.end);
10555
10556            edits.push((start_before..start_before, open_tag));
10557            edits.push((end_after..end_after, close_tag));
10558
10559            boundaries.push((
10560                start_before,
10561                end_after,
10562                wrap_config.start_prefix.len(),
10563                wrap_config.end_suffix.len(),
10564            ));
10565        }
10566
10567        if edits.is_empty() {
10568            return;
10569        }
10570
10571        self.transact(window, cx, |this, window, cx| {
10572            let buffer = this.buffer.update(cx, |buffer, cx| {
10573                buffer.edit(edits, None, cx);
10574                buffer.snapshot(cx)
10575            });
10576
10577            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10578            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10579                boundaries.into_iter()
10580            {
10581                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10582                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10583                new_selections.push(open_offset..open_offset);
10584                new_selections.push(close_offset..close_offset);
10585            }
10586
10587            this.change_selections(Default::default(), window, cx, |s| {
10588                s.select_ranges(new_selections);
10589            });
10590
10591            this.request_autoscroll(Autoscroll::fit(), cx);
10592        });
10593    }
10594
10595    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10596        let Some(project) = self.project.clone() else {
10597            return;
10598        };
10599        self.reload(project, window, cx)
10600            .detach_and_notify_err(window, cx);
10601    }
10602
10603    pub fn restore_file(
10604        &mut self,
10605        _: &::git::RestoreFile,
10606        window: &mut Window,
10607        cx: &mut Context<Self>,
10608    ) {
10609        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10610        let mut buffer_ids = HashSet::default();
10611        let snapshot = self.buffer().read(cx).snapshot(cx);
10612        for selection in self.selections.all::<usize>(cx) {
10613            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10614        }
10615
10616        let buffer = self.buffer().read(cx);
10617        let ranges = buffer_ids
10618            .into_iter()
10619            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10620            .collect::<Vec<_>>();
10621
10622        self.restore_hunks_in_ranges(ranges, window, cx);
10623    }
10624
10625    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10626        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10627        let selections = self
10628            .selections
10629            .all(cx)
10630            .into_iter()
10631            .map(|s| s.range())
10632            .collect();
10633        self.restore_hunks_in_ranges(selections, window, cx);
10634    }
10635
10636    pub fn restore_hunks_in_ranges(
10637        &mut self,
10638        ranges: Vec<Range<Point>>,
10639        window: &mut Window,
10640        cx: &mut Context<Editor>,
10641    ) {
10642        let mut revert_changes = HashMap::default();
10643        let chunk_by = self
10644            .snapshot(window, cx)
10645            .hunks_for_ranges(ranges)
10646            .into_iter()
10647            .chunk_by(|hunk| hunk.buffer_id);
10648        for (buffer_id, hunks) in &chunk_by {
10649            let hunks = hunks.collect::<Vec<_>>();
10650            for hunk in &hunks {
10651                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10652            }
10653            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10654        }
10655        drop(chunk_by);
10656        if !revert_changes.is_empty() {
10657            self.transact(window, cx, |editor, window, cx| {
10658                editor.restore(revert_changes, window, cx);
10659            });
10660        }
10661    }
10662
10663    pub fn open_active_item_in_terminal(
10664        &mut self,
10665        _: &OpenInTerminal,
10666        window: &mut Window,
10667        cx: &mut Context<Self>,
10668    ) {
10669        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10670            let project_path = buffer.read(cx).project_path(cx)?;
10671            let project = self.project()?.read(cx);
10672            let entry = project.entry_for_path(&project_path, cx)?;
10673            let parent = match &entry.canonical_path {
10674                Some(canonical_path) => canonical_path.to_path_buf(),
10675                None => project.absolute_path(&project_path, cx)?,
10676            }
10677            .parent()?
10678            .to_path_buf();
10679            Some(parent)
10680        }) {
10681            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10682        }
10683    }
10684
10685    fn set_breakpoint_context_menu(
10686        &mut self,
10687        display_row: DisplayRow,
10688        position: Option<Anchor>,
10689        clicked_point: gpui::Point<Pixels>,
10690        window: &mut Window,
10691        cx: &mut Context<Self>,
10692    ) {
10693        let source = self
10694            .buffer
10695            .read(cx)
10696            .snapshot(cx)
10697            .anchor_before(Point::new(display_row.0, 0u32));
10698
10699        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10700
10701        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10702            self,
10703            source,
10704            clicked_point,
10705            context_menu,
10706            window,
10707            cx,
10708        );
10709    }
10710
10711    fn add_edit_breakpoint_block(
10712        &mut self,
10713        anchor: Anchor,
10714        breakpoint: &Breakpoint,
10715        edit_action: BreakpointPromptEditAction,
10716        window: &mut Window,
10717        cx: &mut Context<Self>,
10718    ) {
10719        let weak_editor = cx.weak_entity();
10720        let bp_prompt = cx.new(|cx| {
10721            BreakpointPromptEditor::new(
10722                weak_editor,
10723                anchor,
10724                breakpoint.clone(),
10725                edit_action,
10726                window,
10727                cx,
10728            )
10729        });
10730
10731        let height = bp_prompt.update(cx, |this, cx| {
10732            this.prompt
10733                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10734        });
10735        let cloned_prompt = bp_prompt.clone();
10736        let blocks = vec![BlockProperties {
10737            style: BlockStyle::Sticky,
10738            placement: BlockPlacement::Above(anchor),
10739            height: Some(height),
10740            render: Arc::new(move |cx| {
10741                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10742                cloned_prompt.clone().into_any_element()
10743            }),
10744            priority: 0,
10745        }];
10746
10747        let focus_handle = bp_prompt.focus_handle(cx);
10748        window.focus(&focus_handle);
10749
10750        let block_ids = self.insert_blocks(blocks, None, cx);
10751        bp_prompt.update(cx, |prompt, _| {
10752            prompt.add_block_ids(block_ids);
10753        });
10754    }
10755
10756    pub(crate) fn breakpoint_at_row(
10757        &self,
10758        row: u32,
10759        window: &mut Window,
10760        cx: &mut Context<Self>,
10761    ) -> Option<(Anchor, Breakpoint)> {
10762        let snapshot = self.snapshot(window, cx);
10763        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10764
10765        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10766    }
10767
10768    pub(crate) fn breakpoint_at_anchor(
10769        &self,
10770        breakpoint_position: Anchor,
10771        snapshot: &EditorSnapshot,
10772        cx: &mut Context<Self>,
10773    ) -> Option<(Anchor, Breakpoint)> {
10774        let buffer = self
10775            .buffer
10776            .read(cx)
10777            .buffer_for_anchor(breakpoint_position, cx)?;
10778
10779        let enclosing_excerpt = breakpoint_position.excerpt_id;
10780        let buffer_snapshot = buffer.read(cx).snapshot();
10781
10782        let row = buffer_snapshot
10783            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10784            .row;
10785
10786        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10787        let anchor_end = snapshot
10788            .buffer_snapshot
10789            .anchor_after(Point::new(row, line_len));
10790
10791        self.breakpoint_store
10792            .as_ref()?
10793            .read_with(cx, |breakpoint_store, cx| {
10794                breakpoint_store
10795                    .breakpoints(
10796                        &buffer,
10797                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10798                        &buffer_snapshot,
10799                        cx,
10800                    )
10801                    .next()
10802                    .and_then(|(bp, _)| {
10803                        let breakpoint_row = buffer_snapshot
10804                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10805                            .row;
10806
10807                        if breakpoint_row == row {
10808                            snapshot
10809                                .buffer_snapshot
10810                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10811                                .map(|position| (position, bp.bp.clone()))
10812                        } else {
10813                            None
10814                        }
10815                    })
10816            })
10817    }
10818
10819    pub fn edit_log_breakpoint(
10820        &mut self,
10821        _: &EditLogBreakpoint,
10822        window: &mut Window,
10823        cx: &mut Context<Self>,
10824    ) {
10825        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10826            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10827                message: None,
10828                state: BreakpointState::Enabled,
10829                condition: None,
10830                hit_condition: None,
10831            });
10832
10833            self.add_edit_breakpoint_block(
10834                anchor,
10835                &breakpoint,
10836                BreakpointPromptEditAction::Log,
10837                window,
10838                cx,
10839            );
10840        }
10841    }
10842
10843    fn breakpoints_at_cursors(
10844        &self,
10845        window: &mut Window,
10846        cx: &mut Context<Self>,
10847    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10848        let snapshot = self.snapshot(window, cx);
10849        let cursors = self
10850            .selections
10851            .disjoint_anchors_arc()
10852            .iter()
10853            .map(|selection| {
10854                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10855
10856                let breakpoint_position = self
10857                    .breakpoint_at_row(cursor_position.row, window, cx)
10858                    .map(|bp| bp.0)
10859                    .unwrap_or_else(|| {
10860                        snapshot
10861                            .display_snapshot
10862                            .buffer_snapshot
10863                            .anchor_after(Point::new(cursor_position.row, 0))
10864                    });
10865
10866                let breakpoint = self
10867                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10868                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10869
10870                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10871            })
10872            // 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.
10873            .collect::<HashMap<Anchor, _>>();
10874
10875        cursors.into_iter().collect()
10876    }
10877
10878    pub fn enable_breakpoint(
10879        &mut self,
10880        _: &crate::actions::EnableBreakpoint,
10881        window: &mut Window,
10882        cx: &mut Context<Self>,
10883    ) {
10884        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10885            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10886                continue;
10887            };
10888            self.edit_breakpoint_at_anchor(
10889                anchor,
10890                breakpoint,
10891                BreakpointEditAction::InvertState,
10892                cx,
10893            );
10894        }
10895    }
10896
10897    pub fn disable_breakpoint(
10898        &mut self,
10899        _: &crate::actions::DisableBreakpoint,
10900        window: &mut Window,
10901        cx: &mut Context<Self>,
10902    ) {
10903        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10904            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10905                continue;
10906            };
10907            self.edit_breakpoint_at_anchor(
10908                anchor,
10909                breakpoint,
10910                BreakpointEditAction::InvertState,
10911                cx,
10912            );
10913        }
10914    }
10915
10916    pub fn toggle_breakpoint(
10917        &mut self,
10918        _: &crate::actions::ToggleBreakpoint,
10919        window: &mut Window,
10920        cx: &mut Context<Self>,
10921    ) {
10922        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10923            if let Some(breakpoint) = breakpoint {
10924                self.edit_breakpoint_at_anchor(
10925                    anchor,
10926                    breakpoint,
10927                    BreakpointEditAction::Toggle,
10928                    cx,
10929                );
10930            } else {
10931                self.edit_breakpoint_at_anchor(
10932                    anchor,
10933                    Breakpoint::new_standard(),
10934                    BreakpointEditAction::Toggle,
10935                    cx,
10936                );
10937            }
10938        }
10939    }
10940
10941    pub fn edit_breakpoint_at_anchor(
10942        &mut self,
10943        breakpoint_position: Anchor,
10944        breakpoint: Breakpoint,
10945        edit_action: BreakpointEditAction,
10946        cx: &mut Context<Self>,
10947    ) {
10948        let Some(breakpoint_store) = &self.breakpoint_store else {
10949            return;
10950        };
10951
10952        let Some(buffer) = self
10953            .buffer
10954            .read(cx)
10955            .buffer_for_anchor(breakpoint_position, cx)
10956        else {
10957            return;
10958        };
10959
10960        breakpoint_store.update(cx, |breakpoint_store, cx| {
10961            breakpoint_store.toggle_breakpoint(
10962                buffer,
10963                BreakpointWithPosition {
10964                    position: breakpoint_position.text_anchor,
10965                    bp: breakpoint,
10966                },
10967                edit_action,
10968                cx,
10969            );
10970        });
10971
10972        cx.notify();
10973    }
10974
10975    #[cfg(any(test, feature = "test-support"))]
10976    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10977        self.breakpoint_store.clone()
10978    }
10979
10980    pub fn prepare_restore_change(
10981        &self,
10982        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10983        hunk: &MultiBufferDiffHunk,
10984        cx: &mut App,
10985    ) -> Option<()> {
10986        if hunk.is_created_file() {
10987            return None;
10988        }
10989        let buffer = self.buffer.read(cx);
10990        let diff = buffer.diff_for(hunk.buffer_id)?;
10991        let buffer = buffer.buffer(hunk.buffer_id)?;
10992        let buffer = buffer.read(cx);
10993        let original_text = diff
10994            .read(cx)
10995            .base_text()
10996            .as_rope()
10997            .slice(hunk.diff_base_byte_range.clone());
10998        let buffer_snapshot = buffer.snapshot();
10999        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11000        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11001            probe
11002                .0
11003                .start
11004                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11005                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11006        }) {
11007            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11008            Some(())
11009        } else {
11010            None
11011        }
11012    }
11013
11014    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11015        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11016    }
11017
11018    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11019        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11020    }
11021
11022    fn manipulate_lines<M>(
11023        &mut self,
11024        window: &mut Window,
11025        cx: &mut Context<Self>,
11026        mut manipulate: M,
11027    ) where
11028        M: FnMut(&str) -> LineManipulationResult,
11029    {
11030        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11031
11032        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11033        let buffer = self.buffer.read(cx).snapshot(cx);
11034
11035        let mut edits = Vec::new();
11036
11037        let selections = self.selections.all::<Point>(cx);
11038        let mut selections = selections.iter().peekable();
11039        let mut contiguous_row_selections = Vec::new();
11040        let mut new_selections = Vec::new();
11041        let mut added_lines = 0;
11042        let mut removed_lines = 0;
11043
11044        while let Some(selection) = selections.next() {
11045            let (start_row, end_row) = consume_contiguous_rows(
11046                &mut contiguous_row_selections,
11047                selection,
11048                &display_map,
11049                &mut selections,
11050            );
11051
11052            let start_point = Point::new(start_row.0, 0);
11053            let end_point = Point::new(
11054                end_row.previous_row().0,
11055                buffer.line_len(end_row.previous_row()),
11056            );
11057            let text = buffer
11058                .text_for_range(start_point..end_point)
11059                .collect::<String>();
11060
11061            let LineManipulationResult {
11062                new_text,
11063                line_count_before,
11064                line_count_after,
11065            } = manipulate(&text);
11066
11067            edits.push((start_point..end_point, new_text));
11068
11069            // Selections must change based on added and removed line count
11070            let start_row =
11071                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11072            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11073            new_selections.push(Selection {
11074                id: selection.id,
11075                start: start_row,
11076                end: end_row,
11077                goal: SelectionGoal::None,
11078                reversed: selection.reversed,
11079            });
11080
11081            if line_count_after > line_count_before {
11082                added_lines += line_count_after - line_count_before;
11083            } else if line_count_before > line_count_after {
11084                removed_lines += line_count_before - line_count_after;
11085            }
11086        }
11087
11088        self.transact(window, cx, |this, window, cx| {
11089            let buffer = this.buffer.update(cx, |buffer, cx| {
11090                buffer.edit(edits, None, cx);
11091                buffer.snapshot(cx)
11092            });
11093
11094            // Recalculate offsets on newly edited buffer
11095            let new_selections = new_selections
11096                .iter()
11097                .map(|s| {
11098                    let start_point = Point::new(s.start.0, 0);
11099                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11100                    Selection {
11101                        id: s.id,
11102                        start: buffer.point_to_offset(start_point),
11103                        end: buffer.point_to_offset(end_point),
11104                        goal: s.goal,
11105                        reversed: s.reversed,
11106                    }
11107                })
11108                .collect();
11109
11110            this.change_selections(Default::default(), window, cx, |s| {
11111                s.select(new_selections);
11112            });
11113
11114            this.request_autoscroll(Autoscroll::fit(), cx);
11115        });
11116    }
11117
11118    fn manipulate_immutable_lines<Fn>(
11119        &mut self,
11120        window: &mut Window,
11121        cx: &mut Context<Self>,
11122        mut callback: Fn,
11123    ) where
11124        Fn: FnMut(&mut Vec<&str>),
11125    {
11126        self.manipulate_lines(window, cx, |text| {
11127            let mut lines: Vec<&str> = text.split('\n').collect();
11128            let line_count_before = lines.len();
11129
11130            callback(&mut lines);
11131
11132            LineManipulationResult {
11133                new_text: lines.join("\n"),
11134                line_count_before,
11135                line_count_after: lines.len(),
11136            }
11137        });
11138    }
11139
11140    fn manipulate_mutable_lines<Fn>(
11141        &mut self,
11142        window: &mut Window,
11143        cx: &mut Context<Self>,
11144        mut callback: Fn,
11145    ) where
11146        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11147    {
11148        self.manipulate_lines(window, cx, |text| {
11149            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11150            let line_count_before = lines.len();
11151
11152            callback(&mut lines);
11153
11154            LineManipulationResult {
11155                new_text: lines.join("\n"),
11156                line_count_before,
11157                line_count_after: lines.len(),
11158            }
11159        });
11160    }
11161
11162    pub fn convert_indentation_to_spaces(
11163        &mut self,
11164        _: &ConvertIndentationToSpaces,
11165        window: &mut Window,
11166        cx: &mut Context<Self>,
11167    ) {
11168        let settings = self.buffer.read(cx).language_settings(cx);
11169        let tab_size = settings.tab_size.get() as usize;
11170
11171        self.manipulate_mutable_lines(window, cx, |lines| {
11172            // Allocates a reasonably sized scratch buffer once for the whole loop
11173            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11174            // Avoids recomputing spaces that could be inserted many times
11175            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11176                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11177                .collect();
11178
11179            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11180                let mut chars = line.as_ref().chars();
11181                let mut col = 0;
11182                let mut changed = false;
11183
11184                for ch in chars.by_ref() {
11185                    match ch {
11186                        ' ' => {
11187                            reindented_line.push(' ');
11188                            col += 1;
11189                        }
11190                        '\t' => {
11191                            // \t are converted to spaces depending on the current column
11192                            let spaces_len = tab_size - (col % tab_size);
11193                            reindented_line.extend(&space_cache[spaces_len - 1]);
11194                            col += spaces_len;
11195                            changed = true;
11196                        }
11197                        _ => {
11198                            // If we dont append before break, the character is consumed
11199                            reindented_line.push(ch);
11200                            break;
11201                        }
11202                    }
11203                }
11204
11205                if !changed {
11206                    reindented_line.clear();
11207                    continue;
11208                }
11209                // Append the rest of the line and replace old reference with new one
11210                reindented_line.extend(chars);
11211                *line = Cow::Owned(reindented_line.clone());
11212                reindented_line.clear();
11213            }
11214        });
11215    }
11216
11217    pub fn convert_indentation_to_tabs(
11218        &mut self,
11219        _: &ConvertIndentationToTabs,
11220        window: &mut Window,
11221        cx: &mut Context<Self>,
11222    ) {
11223        let settings = self.buffer.read(cx).language_settings(cx);
11224        let tab_size = settings.tab_size.get() as usize;
11225
11226        self.manipulate_mutable_lines(window, cx, |lines| {
11227            // Allocates a reasonably sized buffer once for the whole loop
11228            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11229            // Avoids recomputing spaces that could be inserted many times
11230            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11231                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11232                .collect();
11233
11234            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11235                let mut chars = line.chars();
11236                let mut spaces_count = 0;
11237                let mut first_non_indent_char = None;
11238                let mut changed = false;
11239
11240                for ch in chars.by_ref() {
11241                    match ch {
11242                        ' ' => {
11243                            // Keep track of spaces. Append \t when we reach tab_size
11244                            spaces_count += 1;
11245                            changed = true;
11246                            if spaces_count == tab_size {
11247                                reindented_line.push('\t');
11248                                spaces_count = 0;
11249                            }
11250                        }
11251                        '\t' => {
11252                            reindented_line.push('\t');
11253                            spaces_count = 0;
11254                        }
11255                        _ => {
11256                            // Dont append it yet, we might have remaining spaces
11257                            first_non_indent_char = Some(ch);
11258                            break;
11259                        }
11260                    }
11261                }
11262
11263                if !changed {
11264                    reindented_line.clear();
11265                    continue;
11266                }
11267                // Remaining spaces that didn't make a full tab stop
11268                if spaces_count > 0 {
11269                    reindented_line.extend(&space_cache[spaces_count - 1]);
11270                }
11271                // If we consume an extra character that was not indentation, add it back
11272                if let Some(extra_char) = first_non_indent_char {
11273                    reindented_line.push(extra_char);
11274                }
11275                // Append the rest of the line and replace old reference with new one
11276                reindented_line.extend(chars);
11277                *line = Cow::Owned(reindented_line.clone());
11278                reindented_line.clear();
11279            }
11280        });
11281    }
11282
11283    pub fn convert_to_upper_case(
11284        &mut self,
11285        _: &ConvertToUpperCase,
11286        window: &mut Window,
11287        cx: &mut Context<Self>,
11288    ) {
11289        self.manipulate_text(window, cx, |text| text.to_uppercase())
11290    }
11291
11292    pub fn convert_to_lower_case(
11293        &mut self,
11294        _: &ConvertToLowerCase,
11295        window: &mut Window,
11296        cx: &mut Context<Self>,
11297    ) {
11298        self.manipulate_text(window, cx, |text| text.to_lowercase())
11299    }
11300
11301    pub fn convert_to_title_case(
11302        &mut self,
11303        _: &ConvertToTitleCase,
11304        window: &mut Window,
11305        cx: &mut Context<Self>,
11306    ) {
11307        self.manipulate_text(window, cx, |text| {
11308            text.split('\n')
11309                .map(|line| line.to_case(Case::Title))
11310                .join("\n")
11311        })
11312    }
11313
11314    pub fn convert_to_snake_case(
11315        &mut self,
11316        _: &ConvertToSnakeCase,
11317        window: &mut Window,
11318        cx: &mut Context<Self>,
11319    ) {
11320        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11321    }
11322
11323    pub fn convert_to_kebab_case(
11324        &mut self,
11325        _: &ConvertToKebabCase,
11326        window: &mut Window,
11327        cx: &mut Context<Self>,
11328    ) {
11329        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11330    }
11331
11332    pub fn convert_to_upper_camel_case(
11333        &mut self,
11334        _: &ConvertToUpperCamelCase,
11335        window: &mut Window,
11336        cx: &mut Context<Self>,
11337    ) {
11338        self.manipulate_text(window, cx, |text| {
11339            text.split('\n')
11340                .map(|line| line.to_case(Case::UpperCamel))
11341                .join("\n")
11342        })
11343    }
11344
11345    pub fn convert_to_lower_camel_case(
11346        &mut self,
11347        _: &ConvertToLowerCamelCase,
11348        window: &mut Window,
11349        cx: &mut Context<Self>,
11350    ) {
11351        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11352    }
11353
11354    pub fn convert_to_opposite_case(
11355        &mut self,
11356        _: &ConvertToOppositeCase,
11357        window: &mut Window,
11358        cx: &mut Context<Self>,
11359    ) {
11360        self.manipulate_text(window, cx, |text| {
11361            text.chars()
11362                .fold(String::with_capacity(text.len()), |mut t, c| {
11363                    if c.is_uppercase() {
11364                        t.extend(c.to_lowercase());
11365                    } else {
11366                        t.extend(c.to_uppercase());
11367                    }
11368                    t
11369                })
11370        })
11371    }
11372
11373    pub fn convert_to_sentence_case(
11374        &mut self,
11375        _: &ConvertToSentenceCase,
11376        window: &mut Window,
11377        cx: &mut Context<Self>,
11378    ) {
11379        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11380    }
11381
11382    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11383        self.manipulate_text(window, cx, |text| {
11384            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11385            if has_upper_case_characters {
11386                text.to_lowercase()
11387            } else {
11388                text.to_uppercase()
11389            }
11390        })
11391    }
11392
11393    pub fn convert_to_rot13(
11394        &mut self,
11395        _: &ConvertToRot13,
11396        window: &mut Window,
11397        cx: &mut Context<Self>,
11398    ) {
11399        self.manipulate_text(window, cx, |text| {
11400            text.chars()
11401                .map(|c| match c {
11402                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11403                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11404                    _ => c,
11405                })
11406                .collect()
11407        })
11408    }
11409
11410    pub fn convert_to_rot47(
11411        &mut self,
11412        _: &ConvertToRot47,
11413        window: &mut Window,
11414        cx: &mut Context<Self>,
11415    ) {
11416        self.manipulate_text(window, cx, |text| {
11417            text.chars()
11418                .map(|c| {
11419                    let code_point = c as u32;
11420                    if code_point >= 33 && code_point <= 126 {
11421                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11422                    }
11423                    c
11424                })
11425                .collect()
11426        })
11427    }
11428
11429    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11430    where
11431        Fn: FnMut(&str) -> String,
11432    {
11433        let buffer = self.buffer.read(cx).snapshot(cx);
11434
11435        let mut new_selections = Vec::new();
11436        let mut edits = Vec::new();
11437        let mut selection_adjustment = 0i32;
11438
11439        for selection in self.selections.all_adjusted(cx) {
11440            let selection_is_empty = selection.is_empty();
11441
11442            let (start, end) = if selection_is_empty {
11443                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11444                (word_range.start, word_range.end)
11445            } else {
11446                (
11447                    buffer.point_to_offset(selection.start),
11448                    buffer.point_to_offset(selection.end),
11449                )
11450            };
11451
11452            let text = buffer.text_for_range(start..end).collect::<String>();
11453            let old_length = text.len() as i32;
11454            let text = callback(&text);
11455
11456            new_selections.push(Selection {
11457                start: (start as i32 - selection_adjustment) as usize,
11458                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11459                goal: SelectionGoal::None,
11460                id: selection.id,
11461                reversed: selection.reversed,
11462            });
11463
11464            selection_adjustment += old_length - text.len() as i32;
11465
11466            edits.push((start..end, text));
11467        }
11468
11469        self.transact(window, cx, |this, window, cx| {
11470            this.buffer.update(cx, |buffer, cx| {
11471                buffer.edit(edits, None, cx);
11472            });
11473
11474            this.change_selections(Default::default(), window, cx, |s| {
11475                s.select(new_selections);
11476            });
11477
11478            this.request_autoscroll(Autoscroll::fit(), cx);
11479        });
11480    }
11481
11482    pub fn move_selection_on_drop(
11483        &mut self,
11484        selection: &Selection<Anchor>,
11485        target: DisplayPoint,
11486        is_cut: bool,
11487        window: &mut Window,
11488        cx: &mut Context<Self>,
11489    ) {
11490        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11491        let buffer = &display_map.buffer_snapshot;
11492        let mut edits = Vec::new();
11493        let insert_point = display_map
11494            .clip_point(target, Bias::Left)
11495            .to_point(&display_map);
11496        let text = buffer
11497            .text_for_range(selection.start..selection.end)
11498            .collect::<String>();
11499        if is_cut {
11500            edits.push(((selection.start..selection.end), String::new()));
11501        }
11502        let insert_anchor = buffer.anchor_before(insert_point);
11503        edits.push(((insert_anchor..insert_anchor), text));
11504        let last_edit_start = insert_anchor.bias_left(buffer);
11505        let last_edit_end = insert_anchor.bias_right(buffer);
11506        self.transact(window, cx, |this, window, cx| {
11507            this.buffer.update(cx, |buffer, cx| {
11508                buffer.edit(edits, None, cx);
11509            });
11510            this.change_selections(Default::default(), window, cx, |s| {
11511                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11512            });
11513        });
11514    }
11515
11516    pub fn clear_selection_drag_state(&mut self) {
11517        self.selection_drag_state = SelectionDragState::None;
11518    }
11519
11520    pub fn duplicate(
11521        &mut self,
11522        upwards: bool,
11523        whole_lines: bool,
11524        window: &mut Window,
11525        cx: &mut Context<Self>,
11526    ) {
11527        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11528
11529        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11530        let buffer = &display_map.buffer_snapshot;
11531        let selections = self.selections.all::<Point>(cx);
11532
11533        let mut edits = Vec::new();
11534        let mut selections_iter = selections.iter().peekable();
11535        while let Some(selection) = selections_iter.next() {
11536            let mut rows = selection.spanned_rows(false, &display_map);
11537            // duplicate line-wise
11538            if whole_lines || selection.start == selection.end {
11539                // Avoid duplicating the same lines twice.
11540                while let Some(next_selection) = selections_iter.peek() {
11541                    let next_rows = next_selection.spanned_rows(false, &display_map);
11542                    if next_rows.start < rows.end {
11543                        rows.end = next_rows.end;
11544                        selections_iter.next().unwrap();
11545                    } else {
11546                        break;
11547                    }
11548                }
11549
11550                // Copy the text from the selected row region and splice it either at the start
11551                // or end of the region.
11552                let start = Point::new(rows.start.0, 0);
11553                let end = Point::new(
11554                    rows.end.previous_row().0,
11555                    buffer.line_len(rows.end.previous_row()),
11556                );
11557                let text = buffer
11558                    .text_for_range(start..end)
11559                    .chain(Some("\n"))
11560                    .collect::<String>();
11561                let insert_location = if upwards {
11562                    Point::new(rows.end.0, 0)
11563                } else {
11564                    start
11565                };
11566                edits.push((insert_location..insert_location, text));
11567            } else {
11568                // duplicate character-wise
11569                let start = selection.start;
11570                let end = selection.end;
11571                let text = buffer.text_for_range(start..end).collect::<String>();
11572                edits.push((selection.end..selection.end, text));
11573            }
11574        }
11575
11576        self.transact(window, cx, |this, _, cx| {
11577            this.buffer.update(cx, |buffer, cx| {
11578                buffer.edit(edits, None, cx);
11579            });
11580
11581            this.request_autoscroll(Autoscroll::fit(), cx);
11582        });
11583    }
11584
11585    pub fn duplicate_line_up(
11586        &mut self,
11587        _: &DuplicateLineUp,
11588        window: &mut Window,
11589        cx: &mut Context<Self>,
11590    ) {
11591        self.duplicate(true, true, window, cx);
11592    }
11593
11594    pub fn duplicate_line_down(
11595        &mut self,
11596        _: &DuplicateLineDown,
11597        window: &mut Window,
11598        cx: &mut Context<Self>,
11599    ) {
11600        self.duplicate(false, true, window, cx);
11601    }
11602
11603    pub fn duplicate_selection(
11604        &mut self,
11605        _: &DuplicateSelection,
11606        window: &mut Window,
11607        cx: &mut Context<Self>,
11608    ) {
11609        self.duplicate(false, false, window, cx);
11610    }
11611
11612    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11613        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11614        if self.mode.is_single_line() {
11615            cx.propagate();
11616            return;
11617        }
11618
11619        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11620        let buffer = self.buffer.read(cx).snapshot(cx);
11621
11622        let mut edits = Vec::new();
11623        let mut unfold_ranges = Vec::new();
11624        let mut refold_creases = Vec::new();
11625
11626        let selections = self.selections.all::<Point>(cx);
11627        let mut selections = selections.iter().peekable();
11628        let mut contiguous_row_selections = Vec::new();
11629        let mut new_selections = Vec::new();
11630
11631        while let Some(selection) = selections.next() {
11632            // Find all the selections that span a contiguous row range
11633            let (start_row, end_row) = consume_contiguous_rows(
11634                &mut contiguous_row_selections,
11635                selection,
11636                &display_map,
11637                &mut selections,
11638            );
11639
11640            // Move the text spanned by the row range to be before the line preceding the row range
11641            if start_row.0 > 0 {
11642                let range_to_move = Point::new(
11643                    start_row.previous_row().0,
11644                    buffer.line_len(start_row.previous_row()),
11645                )
11646                    ..Point::new(
11647                        end_row.previous_row().0,
11648                        buffer.line_len(end_row.previous_row()),
11649                    );
11650                let insertion_point = display_map
11651                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11652                    .0;
11653
11654                // Don't move lines across excerpts
11655                if buffer
11656                    .excerpt_containing(insertion_point..range_to_move.end)
11657                    .is_some()
11658                {
11659                    let text = buffer
11660                        .text_for_range(range_to_move.clone())
11661                        .flat_map(|s| s.chars())
11662                        .skip(1)
11663                        .chain(['\n'])
11664                        .collect::<String>();
11665
11666                    edits.push((
11667                        buffer.anchor_after(range_to_move.start)
11668                            ..buffer.anchor_before(range_to_move.end),
11669                        String::new(),
11670                    ));
11671                    let insertion_anchor = buffer.anchor_after(insertion_point);
11672                    edits.push((insertion_anchor..insertion_anchor, text));
11673
11674                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11675
11676                    // Move selections up
11677                    new_selections.extend(contiguous_row_selections.drain(..).map(
11678                        |mut selection| {
11679                            selection.start.row -= row_delta;
11680                            selection.end.row -= row_delta;
11681                            selection
11682                        },
11683                    ));
11684
11685                    // Move folds up
11686                    unfold_ranges.push(range_to_move.clone());
11687                    for fold in display_map.folds_in_range(
11688                        buffer.anchor_before(range_to_move.start)
11689                            ..buffer.anchor_after(range_to_move.end),
11690                    ) {
11691                        let mut start = fold.range.start.to_point(&buffer);
11692                        let mut end = fold.range.end.to_point(&buffer);
11693                        start.row -= row_delta;
11694                        end.row -= row_delta;
11695                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11696                    }
11697                }
11698            }
11699
11700            // If we didn't move line(s), preserve the existing selections
11701            new_selections.append(&mut contiguous_row_selections);
11702        }
11703
11704        self.transact(window, cx, |this, window, cx| {
11705            this.unfold_ranges(&unfold_ranges, true, true, cx);
11706            this.buffer.update(cx, |buffer, cx| {
11707                for (range, text) in edits {
11708                    buffer.edit([(range, text)], None, cx);
11709                }
11710            });
11711            this.fold_creases(refold_creases, true, window, cx);
11712            this.change_selections(Default::default(), window, cx, |s| {
11713                s.select(new_selections);
11714            })
11715        });
11716    }
11717
11718    pub fn move_line_down(
11719        &mut self,
11720        _: &MoveLineDown,
11721        window: &mut Window,
11722        cx: &mut Context<Self>,
11723    ) {
11724        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11725        if self.mode.is_single_line() {
11726            cx.propagate();
11727            return;
11728        }
11729
11730        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11731        let buffer = self.buffer.read(cx).snapshot(cx);
11732
11733        let mut edits = Vec::new();
11734        let mut unfold_ranges = Vec::new();
11735        let mut refold_creases = Vec::new();
11736
11737        let selections = self.selections.all::<Point>(cx);
11738        let mut selections = selections.iter().peekable();
11739        let mut contiguous_row_selections = Vec::new();
11740        let mut new_selections = Vec::new();
11741
11742        while let Some(selection) = selections.next() {
11743            // Find all the selections that span a contiguous row range
11744            let (start_row, end_row) = consume_contiguous_rows(
11745                &mut contiguous_row_selections,
11746                selection,
11747                &display_map,
11748                &mut selections,
11749            );
11750
11751            // Move the text spanned by the row range to be after the last line of the row range
11752            if end_row.0 <= buffer.max_point().row {
11753                let range_to_move =
11754                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11755                let insertion_point = display_map
11756                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11757                    .0;
11758
11759                // Don't move lines across excerpt boundaries
11760                if buffer
11761                    .excerpt_containing(range_to_move.start..insertion_point)
11762                    .is_some()
11763                {
11764                    let mut text = String::from("\n");
11765                    text.extend(buffer.text_for_range(range_to_move.clone()));
11766                    text.pop(); // Drop trailing newline
11767                    edits.push((
11768                        buffer.anchor_after(range_to_move.start)
11769                            ..buffer.anchor_before(range_to_move.end),
11770                        String::new(),
11771                    ));
11772                    let insertion_anchor = buffer.anchor_after(insertion_point);
11773                    edits.push((insertion_anchor..insertion_anchor, text));
11774
11775                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11776
11777                    // Move selections down
11778                    new_selections.extend(contiguous_row_selections.drain(..).map(
11779                        |mut selection| {
11780                            selection.start.row += row_delta;
11781                            selection.end.row += row_delta;
11782                            selection
11783                        },
11784                    ));
11785
11786                    // Move folds down
11787                    unfold_ranges.push(range_to_move.clone());
11788                    for fold in display_map.folds_in_range(
11789                        buffer.anchor_before(range_to_move.start)
11790                            ..buffer.anchor_after(range_to_move.end),
11791                    ) {
11792                        let mut start = fold.range.start.to_point(&buffer);
11793                        let mut end = fold.range.end.to_point(&buffer);
11794                        start.row += row_delta;
11795                        end.row += row_delta;
11796                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11797                    }
11798                }
11799            }
11800
11801            // If we didn't move line(s), preserve the existing selections
11802            new_selections.append(&mut contiguous_row_selections);
11803        }
11804
11805        self.transact(window, cx, |this, window, cx| {
11806            this.unfold_ranges(&unfold_ranges, true, true, cx);
11807            this.buffer.update(cx, |buffer, cx| {
11808                for (range, text) in edits {
11809                    buffer.edit([(range, text)], None, cx);
11810                }
11811            });
11812            this.fold_creases(refold_creases, true, window, cx);
11813            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11814        });
11815    }
11816
11817    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11818        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11819        let text_layout_details = &self.text_layout_details(window);
11820        self.transact(window, cx, |this, window, cx| {
11821            let edits = this.change_selections(Default::default(), window, cx, |s| {
11822                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11823                s.move_with(|display_map, selection| {
11824                    if !selection.is_empty() {
11825                        return;
11826                    }
11827
11828                    let mut head = selection.head();
11829                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11830                    if head.column() == display_map.line_len(head.row()) {
11831                        transpose_offset = display_map
11832                            .buffer_snapshot
11833                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11834                    }
11835
11836                    if transpose_offset == 0 {
11837                        return;
11838                    }
11839
11840                    *head.column_mut() += 1;
11841                    head = display_map.clip_point(head, Bias::Right);
11842                    let goal = SelectionGoal::HorizontalPosition(
11843                        display_map
11844                            .x_for_display_point(head, text_layout_details)
11845                            .into(),
11846                    );
11847                    selection.collapse_to(head, goal);
11848
11849                    let transpose_start = display_map
11850                        .buffer_snapshot
11851                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11852                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11853                        let transpose_end = display_map
11854                            .buffer_snapshot
11855                            .clip_offset(transpose_offset + 1, Bias::Right);
11856                        if let Some(ch) =
11857                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11858                        {
11859                            edits.push((transpose_start..transpose_offset, String::new()));
11860                            edits.push((transpose_end..transpose_end, ch.to_string()));
11861                        }
11862                    }
11863                });
11864                edits
11865            });
11866            this.buffer
11867                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11868            let selections = this.selections.all::<usize>(cx);
11869            this.change_selections(Default::default(), window, cx, |s| {
11870                s.select(selections);
11871            });
11872        });
11873    }
11874
11875    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11876        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11877        if self.mode.is_single_line() {
11878            cx.propagate();
11879            return;
11880        }
11881
11882        self.rewrap_impl(RewrapOptions::default(), cx)
11883    }
11884
11885    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11886        let buffer = self.buffer.read(cx).snapshot(cx);
11887        let selections = self.selections.all::<Point>(cx);
11888
11889        #[derive(Clone, Debug, PartialEq)]
11890        enum CommentFormat {
11891            /// single line comment, with prefix for line
11892            Line(String),
11893            /// single line within a block comment, with prefix for line
11894            BlockLine(String),
11895            /// a single line of a block comment that includes the initial delimiter
11896            BlockCommentWithStart(BlockCommentConfig),
11897            /// a single line of a block comment that includes the ending delimiter
11898            BlockCommentWithEnd(BlockCommentConfig),
11899        }
11900
11901        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11902        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11903            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11904                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11905                .peekable();
11906
11907            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11908                row
11909            } else {
11910                return Vec::new();
11911            };
11912
11913            let language_settings = buffer.language_settings_at(selection.head(), cx);
11914            let language_scope = buffer.language_scope_at(selection.head());
11915
11916            let indent_and_prefix_for_row =
11917                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11918                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11919                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11920                        &language_scope
11921                    {
11922                        let indent_end = Point::new(row, indent.len);
11923                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11924                        let line_text_after_indent = buffer
11925                            .text_for_range(indent_end..line_end)
11926                            .collect::<String>();
11927
11928                        let is_within_comment_override = buffer
11929                            .language_scope_at(indent_end)
11930                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11931                        let comment_delimiters = if is_within_comment_override {
11932                            // we are within a comment syntax node, but we don't
11933                            // yet know what kind of comment: block, doc or line
11934                            match (
11935                                language_scope.documentation_comment(),
11936                                language_scope.block_comment(),
11937                            ) {
11938                                (Some(config), _) | (_, Some(config))
11939                                    if buffer.contains_str_at(indent_end, &config.start) =>
11940                                {
11941                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11942                                }
11943                                (Some(config), _) | (_, Some(config))
11944                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11945                                {
11946                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11947                                }
11948                                (Some(config), _) | (_, Some(config))
11949                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11950                                {
11951                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11952                                }
11953                                (_, _) => language_scope
11954                                    .line_comment_prefixes()
11955                                    .iter()
11956                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11957                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11958                            }
11959                        } else {
11960                            // we not in an overridden comment node, but we may
11961                            // be within a non-overridden line comment node
11962                            language_scope
11963                                .line_comment_prefixes()
11964                                .iter()
11965                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11966                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11967                        };
11968
11969                        let rewrap_prefix = language_scope
11970                            .rewrap_prefixes()
11971                            .iter()
11972                            .find_map(|prefix_regex| {
11973                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11974                                    if mat.start() == 0 {
11975                                        Some(mat.as_str().to_string())
11976                                    } else {
11977                                        None
11978                                    }
11979                                })
11980                            })
11981                            .flatten();
11982                        (comment_delimiters, rewrap_prefix)
11983                    } else {
11984                        (None, None)
11985                    };
11986                    (indent, comment_prefix, rewrap_prefix)
11987                };
11988
11989            let mut ranges = Vec::new();
11990            let from_empty_selection = selection.is_empty();
11991
11992            let mut current_range_start = first_row;
11993            let mut prev_row = first_row;
11994            let (
11995                mut current_range_indent,
11996                mut current_range_comment_delimiters,
11997                mut current_range_rewrap_prefix,
11998            ) = indent_and_prefix_for_row(first_row);
11999
12000            for row in non_blank_rows_iter.skip(1) {
12001                let has_paragraph_break = row > prev_row + 1;
12002
12003                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12004                    indent_and_prefix_for_row(row);
12005
12006                let has_indent_change = row_indent != current_range_indent;
12007                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12008
12009                let has_boundary_change = has_comment_change
12010                    || row_rewrap_prefix.is_some()
12011                    || (has_indent_change && current_range_comment_delimiters.is_some());
12012
12013                if has_paragraph_break || has_boundary_change {
12014                    ranges.push((
12015                        language_settings.clone(),
12016                        Point::new(current_range_start, 0)
12017                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12018                        current_range_indent,
12019                        current_range_comment_delimiters.clone(),
12020                        current_range_rewrap_prefix.clone(),
12021                        from_empty_selection,
12022                    ));
12023                    current_range_start = row;
12024                    current_range_indent = row_indent;
12025                    current_range_comment_delimiters = row_comment_delimiters;
12026                    current_range_rewrap_prefix = row_rewrap_prefix;
12027                }
12028                prev_row = row;
12029            }
12030
12031            ranges.push((
12032                language_settings.clone(),
12033                Point::new(current_range_start, 0)
12034                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12035                current_range_indent,
12036                current_range_comment_delimiters,
12037                current_range_rewrap_prefix,
12038                from_empty_selection,
12039            ));
12040
12041            ranges
12042        });
12043
12044        let mut edits = Vec::new();
12045        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12046
12047        for (
12048            language_settings,
12049            wrap_range,
12050            mut indent_size,
12051            comment_prefix,
12052            rewrap_prefix,
12053            from_empty_selection,
12054        ) in wrap_ranges
12055        {
12056            let mut start_row = wrap_range.start.row;
12057            let mut end_row = wrap_range.end.row;
12058
12059            // Skip selections that overlap with a range that has already been rewrapped.
12060            let selection_range = start_row..end_row;
12061            if rewrapped_row_ranges
12062                .iter()
12063                .any(|range| range.overlaps(&selection_range))
12064            {
12065                continue;
12066            }
12067
12068            let tab_size = language_settings.tab_size;
12069
12070            let (line_prefix, inside_comment) = match &comment_prefix {
12071                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12072                    (Some(prefix.as_str()), true)
12073                }
12074                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12075                    (Some(prefix.as_ref()), true)
12076                }
12077                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12078                    start: _,
12079                    end: _,
12080                    prefix,
12081                    tab_size,
12082                })) => {
12083                    indent_size.len += tab_size;
12084                    (Some(prefix.as_ref()), true)
12085                }
12086                None => (None, false),
12087            };
12088            let indent_prefix = indent_size.chars().collect::<String>();
12089            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12090
12091            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12092                RewrapBehavior::InComments => inside_comment,
12093                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12094                RewrapBehavior::Anywhere => true,
12095            };
12096
12097            let should_rewrap = options.override_language_settings
12098                || allow_rewrap_based_on_language
12099                || self.hard_wrap.is_some();
12100            if !should_rewrap {
12101                continue;
12102            }
12103
12104            if from_empty_selection {
12105                'expand_upwards: while start_row > 0 {
12106                    let prev_row = start_row - 1;
12107                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12108                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12109                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12110                    {
12111                        start_row = prev_row;
12112                    } else {
12113                        break 'expand_upwards;
12114                    }
12115                }
12116
12117                'expand_downwards: while end_row < buffer.max_point().row {
12118                    let next_row = end_row + 1;
12119                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12120                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12121                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12122                    {
12123                        end_row = next_row;
12124                    } else {
12125                        break 'expand_downwards;
12126                    }
12127                }
12128            }
12129
12130            let start = Point::new(start_row, 0);
12131            let start_offset = start.to_offset(&buffer);
12132            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12133            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12134            let mut first_line_delimiter = None;
12135            let mut last_line_delimiter = None;
12136            let Some(lines_without_prefixes) = selection_text
12137                .lines()
12138                .enumerate()
12139                .map(|(ix, line)| {
12140                    let line_trimmed = line.trim_start();
12141                    if rewrap_prefix.is_some() && ix > 0 {
12142                        Ok(line_trimmed)
12143                    } else if let Some(
12144                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12145                            start,
12146                            prefix,
12147                            end,
12148                            tab_size,
12149                        })
12150                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12151                            start,
12152                            prefix,
12153                            end,
12154                            tab_size,
12155                        }),
12156                    ) = &comment_prefix
12157                    {
12158                        let line_trimmed = line_trimmed
12159                            .strip_prefix(start.as_ref())
12160                            .map(|s| {
12161                                let mut indent_size = indent_size;
12162                                indent_size.len -= tab_size;
12163                                let indent_prefix: String = indent_size.chars().collect();
12164                                first_line_delimiter = Some((indent_prefix, start));
12165                                s.trim_start()
12166                            })
12167                            .unwrap_or(line_trimmed);
12168                        let line_trimmed = line_trimmed
12169                            .strip_suffix(end.as_ref())
12170                            .map(|s| {
12171                                last_line_delimiter = Some(end);
12172                                s.trim_end()
12173                            })
12174                            .unwrap_or(line_trimmed);
12175                        let line_trimmed = line_trimmed
12176                            .strip_prefix(prefix.as_ref())
12177                            .unwrap_or(line_trimmed);
12178                        Ok(line_trimmed)
12179                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12180                        line_trimmed.strip_prefix(prefix).with_context(|| {
12181                            format!("line did not start with prefix {prefix:?}: {line:?}")
12182                        })
12183                    } else {
12184                        line_trimmed
12185                            .strip_prefix(&line_prefix.trim_start())
12186                            .with_context(|| {
12187                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12188                            })
12189                    }
12190                })
12191                .collect::<Result<Vec<_>, _>>()
12192                .log_err()
12193            else {
12194                continue;
12195            };
12196
12197            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12198                buffer
12199                    .language_settings_at(Point::new(start_row, 0), cx)
12200                    .preferred_line_length as usize
12201            });
12202
12203            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12204                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12205            } else {
12206                line_prefix.clone()
12207            };
12208
12209            let wrapped_text = {
12210                let mut wrapped_text = wrap_with_prefix(
12211                    line_prefix,
12212                    subsequent_lines_prefix,
12213                    lines_without_prefixes.join("\n"),
12214                    wrap_column,
12215                    tab_size,
12216                    options.preserve_existing_whitespace,
12217                );
12218
12219                if let Some((indent, delimiter)) = first_line_delimiter {
12220                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12221                }
12222                if let Some(last_line) = last_line_delimiter {
12223                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12224                }
12225
12226                wrapped_text
12227            };
12228
12229            // TODO: should always use char-based diff while still supporting cursor behavior that
12230            // matches vim.
12231            let mut diff_options = DiffOptions::default();
12232            if options.override_language_settings {
12233                diff_options.max_word_diff_len = 0;
12234                diff_options.max_word_diff_line_count = 0;
12235            } else {
12236                diff_options.max_word_diff_len = usize::MAX;
12237                diff_options.max_word_diff_line_count = usize::MAX;
12238            }
12239
12240            for (old_range, new_text) in
12241                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12242            {
12243                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12244                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12245                edits.push((edit_start..edit_end, new_text));
12246            }
12247
12248            rewrapped_row_ranges.push(start_row..=end_row);
12249        }
12250
12251        self.buffer
12252            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12253    }
12254
12255    pub fn cut_common(
12256        &mut self,
12257        cut_no_selection_line: bool,
12258        window: &mut Window,
12259        cx: &mut Context<Self>,
12260    ) -> ClipboardItem {
12261        let mut text = String::new();
12262        let buffer = self.buffer.read(cx).snapshot(cx);
12263        let mut selections = self.selections.all::<Point>(cx);
12264        let mut clipboard_selections = Vec::with_capacity(selections.len());
12265        {
12266            let max_point = buffer.max_point();
12267            let mut is_first = true;
12268            for selection in &mut selections {
12269                let is_entire_line =
12270                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode;
12271                if is_entire_line {
12272                    selection.start = Point::new(selection.start.row, 0);
12273                    if !selection.is_empty() && selection.end.column == 0 {
12274                        selection.end = cmp::min(max_point, selection.end);
12275                    } else {
12276                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12277                    }
12278                    selection.goal = SelectionGoal::None;
12279                }
12280                if is_first {
12281                    is_first = false;
12282                } else {
12283                    text += "\n";
12284                }
12285                let mut len = 0;
12286                for chunk in buffer.text_for_range(selection.start..selection.end) {
12287                    text.push_str(chunk);
12288                    len += chunk.len();
12289                }
12290                clipboard_selections.push(ClipboardSelection {
12291                    len,
12292                    is_entire_line,
12293                    first_line_indent: buffer
12294                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12295                        .len,
12296                });
12297            }
12298        }
12299
12300        self.transact(window, cx, |this, window, cx| {
12301            this.change_selections(Default::default(), window, cx, |s| {
12302                s.select(selections);
12303            });
12304            this.insert("", window, cx);
12305        });
12306        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12307    }
12308
12309    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12310        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12311        let item = self.cut_common(true, window, cx);
12312        cx.write_to_clipboard(item);
12313    }
12314
12315    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12316        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12317        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12318            s.move_with(|snapshot, sel| {
12319                if sel.is_empty() {
12320                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12321                }
12322                if sel.is_empty() {
12323                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12324                }
12325            });
12326        });
12327        let item = self.cut_common(true, window, cx);
12328        cx.set_global(KillRing(item))
12329    }
12330
12331    pub fn kill_ring_yank(
12332        &mut self,
12333        _: &KillRingYank,
12334        window: &mut Window,
12335        cx: &mut Context<Self>,
12336    ) {
12337        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12338        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12339            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12340                (kill_ring.text().to_string(), kill_ring.metadata_json())
12341            } else {
12342                return;
12343            }
12344        } else {
12345            return;
12346        };
12347        self.do_paste(&text, metadata, false, window, cx);
12348    }
12349
12350    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12351        self.do_copy(true, cx);
12352    }
12353
12354    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12355        self.do_copy(false, cx);
12356    }
12357
12358    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12359        let selections = self.selections.all::<Point>(cx);
12360        let buffer = self.buffer.read(cx).read(cx);
12361        let mut text = String::new();
12362
12363        let mut clipboard_selections = Vec::with_capacity(selections.len());
12364        {
12365            let max_point = buffer.max_point();
12366            let mut is_first = true;
12367            for selection in &selections {
12368                let mut start = selection.start;
12369                let mut end = selection.end;
12370                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12371                if is_entire_line {
12372                    start = Point::new(start.row, 0);
12373                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12374                }
12375
12376                let mut trimmed_selections = Vec::new();
12377                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12378                    let row = MultiBufferRow(start.row);
12379                    let first_indent = buffer.indent_size_for_line(row);
12380                    if first_indent.len == 0 || start.column > first_indent.len {
12381                        trimmed_selections.push(start..end);
12382                    } else {
12383                        trimmed_selections.push(
12384                            Point::new(row.0, first_indent.len)
12385                                ..Point::new(row.0, buffer.line_len(row)),
12386                        );
12387                        for row in start.row + 1..=end.row {
12388                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12389                            if row == end.row {
12390                                line_len = end.column;
12391                            }
12392                            if line_len == 0 {
12393                                trimmed_selections
12394                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12395                                continue;
12396                            }
12397                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12398                            if row_indent_size.len >= first_indent.len {
12399                                trimmed_selections.push(
12400                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12401                                );
12402                            } else {
12403                                trimmed_selections.clear();
12404                                trimmed_selections.push(start..end);
12405                                break;
12406                            }
12407                        }
12408                    }
12409                } else {
12410                    trimmed_selections.push(start..end);
12411                }
12412
12413                for trimmed_range in trimmed_selections {
12414                    if is_first {
12415                        is_first = false;
12416                    } else {
12417                        text += "\n";
12418                    }
12419                    let mut len = 0;
12420                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12421                        text.push_str(chunk);
12422                        len += chunk.len();
12423                    }
12424                    clipboard_selections.push(ClipboardSelection {
12425                        len,
12426                        is_entire_line,
12427                        first_line_indent: buffer
12428                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12429                            .len,
12430                    });
12431                }
12432            }
12433        }
12434
12435        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12436            text,
12437            clipboard_selections,
12438        ));
12439    }
12440
12441    pub fn do_paste(
12442        &mut self,
12443        text: &String,
12444        clipboard_selections: Option<Vec<ClipboardSelection>>,
12445        handle_entire_lines: bool,
12446        window: &mut Window,
12447        cx: &mut Context<Self>,
12448    ) {
12449        if self.read_only(cx) {
12450            return;
12451        }
12452
12453        let clipboard_text = Cow::Borrowed(text);
12454
12455        self.transact(window, cx, |this, window, cx| {
12456            let had_active_edit_prediction = this.has_active_edit_prediction();
12457
12458            if let Some(mut clipboard_selections) = clipboard_selections {
12459                let old_selections = this.selections.all::<usize>(cx);
12460                let all_selections_were_entire_line =
12461                    clipboard_selections.iter().all(|s| s.is_entire_line);
12462                let first_selection_indent_column =
12463                    clipboard_selections.first().map(|s| s.first_line_indent);
12464                if clipboard_selections.len() != old_selections.len() {
12465                    clipboard_selections.drain(..);
12466                }
12467                let cursor_offset = this.selections.last::<usize>(cx).head();
12468                let mut auto_indent_on_paste = true;
12469
12470                this.buffer.update(cx, |buffer, cx| {
12471                    let snapshot = buffer.read(cx);
12472                    auto_indent_on_paste = snapshot
12473                        .language_settings_at(cursor_offset, cx)
12474                        .auto_indent_on_paste;
12475
12476                    let mut start_offset = 0;
12477                    let mut edits = Vec::new();
12478                    let mut original_indent_columns = Vec::new();
12479                    for (ix, selection) in old_selections.iter().enumerate() {
12480                        let to_insert;
12481                        let entire_line;
12482                        let original_indent_column;
12483                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12484                            let end_offset = start_offset + clipboard_selection.len;
12485                            to_insert = &clipboard_text[start_offset..end_offset];
12486                            entire_line = clipboard_selection.is_entire_line;
12487                            start_offset = end_offset + 1;
12488                            original_indent_column = Some(clipboard_selection.first_line_indent);
12489                        } else {
12490                            to_insert = clipboard_text.as_str();
12491                            entire_line = all_selections_were_entire_line;
12492                            original_indent_column = first_selection_indent_column
12493                        }
12494
12495                        // If the corresponding selection was empty when this slice of the
12496                        // clipboard text was written, then the entire line containing the
12497                        // selection was copied. If this selection is also currently empty,
12498                        // then paste the line before the current line of the buffer.
12499                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12500                            let column = selection.start.to_point(&snapshot).column as usize;
12501                            let line_start = selection.start - column;
12502                            line_start..line_start
12503                        } else {
12504                            selection.range()
12505                        };
12506
12507                        edits.push((range, to_insert));
12508                        original_indent_columns.push(original_indent_column);
12509                    }
12510                    drop(snapshot);
12511
12512                    buffer.edit(
12513                        edits,
12514                        if auto_indent_on_paste {
12515                            Some(AutoindentMode::Block {
12516                                original_indent_columns,
12517                            })
12518                        } else {
12519                            None
12520                        },
12521                        cx,
12522                    );
12523                });
12524
12525                let selections = this.selections.all::<usize>(cx);
12526                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12527            } else {
12528                this.insert(&clipboard_text, window, cx);
12529            }
12530
12531            let trigger_in_words =
12532                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12533
12534            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12535        });
12536    }
12537
12538    pub fn diff_clipboard_with_selection(
12539        &mut self,
12540        _: &DiffClipboardWithSelection,
12541        window: &mut Window,
12542        cx: &mut Context<Self>,
12543    ) {
12544        let selections = self.selections.all::<usize>(cx);
12545
12546        if selections.is_empty() {
12547            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12548            return;
12549        };
12550
12551        let clipboard_text = match cx.read_from_clipboard() {
12552            Some(item) => match item.entries().first() {
12553                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12554                _ => None,
12555            },
12556            None => None,
12557        };
12558
12559        let Some(clipboard_text) = clipboard_text else {
12560            log::warn!("Clipboard doesn't contain text.");
12561            return;
12562        };
12563
12564        window.dispatch_action(
12565            Box::new(DiffClipboardWithSelectionData {
12566                clipboard_text,
12567                editor: cx.entity(),
12568            }),
12569            cx,
12570        );
12571    }
12572
12573    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12574        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12575        if let Some(item) = cx.read_from_clipboard() {
12576            let entries = item.entries();
12577
12578            match entries.first() {
12579                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12580                // of all the pasted entries.
12581                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12582                    .do_paste(
12583                        clipboard_string.text(),
12584                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12585                        true,
12586                        window,
12587                        cx,
12588                    ),
12589                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12590            }
12591        }
12592    }
12593
12594    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12595        if self.read_only(cx) {
12596            return;
12597        }
12598
12599        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12600
12601        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12602            if let Some((selections, _)) =
12603                self.selection_history.transaction(transaction_id).cloned()
12604            {
12605                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12606                    s.select_anchors(selections.to_vec());
12607                });
12608            } else {
12609                log::error!(
12610                    "No entry in selection_history found for undo. \
12611                     This may correspond to a bug where undo does not update the selection. \
12612                     If this is occurring, please add details to \
12613                     https://github.com/zed-industries/zed/issues/22692"
12614                );
12615            }
12616            self.request_autoscroll(Autoscroll::fit(), cx);
12617            self.unmark_text(window, cx);
12618            self.refresh_edit_prediction(true, false, window, cx);
12619            cx.emit(EditorEvent::Edited { transaction_id });
12620            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12621        }
12622    }
12623
12624    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12625        if self.read_only(cx) {
12626            return;
12627        }
12628
12629        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12630
12631        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12632            if let Some((_, Some(selections))) =
12633                self.selection_history.transaction(transaction_id).cloned()
12634            {
12635                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12636                    s.select_anchors(selections.to_vec());
12637                });
12638            } else {
12639                log::error!(
12640                    "No entry in selection_history found for redo. \
12641                     This may correspond to a bug where undo does not update the selection. \
12642                     If this is occurring, please add details to \
12643                     https://github.com/zed-industries/zed/issues/22692"
12644                );
12645            }
12646            self.request_autoscroll(Autoscroll::fit(), cx);
12647            self.unmark_text(window, cx);
12648            self.refresh_edit_prediction(true, false, window, cx);
12649            cx.emit(EditorEvent::Edited { transaction_id });
12650        }
12651    }
12652
12653    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12654        self.buffer
12655            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12656    }
12657
12658    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12659        self.buffer
12660            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12661    }
12662
12663    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12664        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12665        self.change_selections(Default::default(), window, cx, |s| {
12666            s.move_with(|map, selection| {
12667                let cursor = if selection.is_empty() {
12668                    movement::left(map, selection.start)
12669                } else {
12670                    selection.start
12671                };
12672                selection.collapse_to(cursor, SelectionGoal::None);
12673            });
12674        })
12675    }
12676
12677    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12678        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12679        self.change_selections(Default::default(), window, cx, |s| {
12680            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12681        })
12682    }
12683
12684    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12685        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12686        self.change_selections(Default::default(), window, cx, |s| {
12687            s.move_with(|map, selection| {
12688                let cursor = if selection.is_empty() {
12689                    movement::right(map, selection.end)
12690                } else {
12691                    selection.end
12692                };
12693                selection.collapse_to(cursor, SelectionGoal::None)
12694            });
12695        })
12696    }
12697
12698    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12699        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12700        self.change_selections(Default::default(), window, cx, |s| {
12701            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12702        })
12703    }
12704
12705    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12706        if self.take_rename(true, window, cx).is_some() {
12707            return;
12708        }
12709
12710        if self.mode.is_single_line() {
12711            cx.propagate();
12712            return;
12713        }
12714
12715        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12716
12717        let text_layout_details = &self.text_layout_details(window);
12718        let selection_count = self.selections.count();
12719        let first_selection = self.selections.first_anchor();
12720
12721        self.change_selections(Default::default(), window, cx, |s| {
12722            s.move_with(|map, selection| {
12723                if !selection.is_empty() {
12724                    selection.goal = SelectionGoal::None;
12725                }
12726                let (cursor, goal) = movement::up(
12727                    map,
12728                    selection.start,
12729                    selection.goal,
12730                    false,
12731                    text_layout_details,
12732                );
12733                selection.collapse_to(cursor, goal);
12734            });
12735        });
12736
12737        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12738        {
12739            cx.propagate();
12740        }
12741    }
12742
12743    pub fn move_up_by_lines(
12744        &mut self,
12745        action: &MoveUpByLines,
12746        window: &mut Window,
12747        cx: &mut Context<Self>,
12748    ) {
12749        if self.take_rename(true, window, cx).is_some() {
12750            return;
12751        }
12752
12753        if self.mode.is_single_line() {
12754            cx.propagate();
12755            return;
12756        }
12757
12758        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12759
12760        let text_layout_details = &self.text_layout_details(window);
12761
12762        self.change_selections(Default::default(), window, cx, |s| {
12763            s.move_with(|map, selection| {
12764                if !selection.is_empty() {
12765                    selection.goal = SelectionGoal::None;
12766                }
12767                let (cursor, goal) = movement::up_by_rows(
12768                    map,
12769                    selection.start,
12770                    action.lines,
12771                    selection.goal,
12772                    false,
12773                    text_layout_details,
12774                );
12775                selection.collapse_to(cursor, goal);
12776            });
12777        })
12778    }
12779
12780    pub fn move_down_by_lines(
12781        &mut self,
12782        action: &MoveDownByLines,
12783        window: &mut Window,
12784        cx: &mut Context<Self>,
12785    ) {
12786        if self.take_rename(true, window, cx).is_some() {
12787            return;
12788        }
12789
12790        if self.mode.is_single_line() {
12791            cx.propagate();
12792            return;
12793        }
12794
12795        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12796
12797        let text_layout_details = &self.text_layout_details(window);
12798
12799        self.change_selections(Default::default(), window, cx, |s| {
12800            s.move_with(|map, selection| {
12801                if !selection.is_empty() {
12802                    selection.goal = SelectionGoal::None;
12803                }
12804                let (cursor, goal) = movement::down_by_rows(
12805                    map,
12806                    selection.start,
12807                    action.lines,
12808                    selection.goal,
12809                    false,
12810                    text_layout_details,
12811                );
12812                selection.collapse_to(cursor, goal);
12813            });
12814        })
12815    }
12816
12817    pub fn select_down_by_lines(
12818        &mut self,
12819        action: &SelectDownByLines,
12820        window: &mut Window,
12821        cx: &mut Context<Self>,
12822    ) {
12823        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12824        let text_layout_details = &self.text_layout_details(window);
12825        self.change_selections(Default::default(), window, cx, |s| {
12826            s.move_heads_with(|map, head, goal| {
12827                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12828            })
12829        })
12830    }
12831
12832    pub fn select_up_by_lines(
12833        &mut self,
12834        action: &SelectUpByLines,
12835        window: &mut Window,
12836        cx: &mut Context<Self>,
12837    ) {
12838        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12839        let text_layout_details = &self.text_layout_details(window);
12840        self.change_selections(Default::default(), window, cx, |s| {
12841            s.move_heads_with(|map, head, goal| {
12842                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12843            })
12844        })
12845    }
12846
12847    pub fn select_page_up(
12848        &mut self,
12849        _: &SelectPageUp,
12850        window: &mut Window,
12851        cx: &mut Context<Self>,
12852    ) {
12853        let Some(row_count) = self.visible_row_count() else {
12854            return;
12855        };
12856
12857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12858
12859        let text_layout_details = &self.text_layout_details(window);
12860
12861        self.change_selections(Default::default(), window, cx, |s| {
12862            s.move_heads_with(|map, head, goal| {
12863                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12864            })
12865        })
12866    }
12867
12868    pub fn move_page_up(
12869        &mut self,
12870        action: &MovePageUp,
12871        window: &mut Window,
12872        cx: &mut Context<Self>,
12873    ) {
12874        if self.take_rename(true, window, cx).is_some() {
12875            return;
12876        }
12877
12878        if self
12879            .context_menu
12880            .borrow_mut()
12881            .as_mut()
12882            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12883            .unwrap_or(false)
12884        {
12885            return;
12886        }
12887
12888        if matches!(self.mode, EditorMode::SingleLine) {
12889            cx.propagate();
12890            return;
12891        }
12892
12893        let Some(row_count) = self.visible_row_count() else {
12894            return;
12895        };
12896
12897        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12898
12899        let effects = if action.center_cursor {
12900            SelectionEffects::scroll(Autoscroll::center())
12901        } else {
12902            SelectionEffects::default()
12903        };
12904
12905        let text_layout_details = &self.text_layout_details(window);
12906
12907        self.change_selections(effects, window, cx, |s| {
12908            s.move_with(|map, selection| {
12909                if !selection.is_empty() {
12910                    selection.goal = SelectionGoal::None;
12911                }
12912                let (cursor, goal) = movement::up_by_rows(
12913                    map,
12914                    selection.end,
12915                    row_count,
12916                    selection.goal,
12917                    false,
12918                    text_layout_details,
12919                );
12920                selection.collapse_to(cursor, goal);
12921            });
12922        });
12923    }
12924
12925    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12926        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12927        let text_layout_details = &self.text_layout_details(window);
12928        self.change_selections(Default::default(), window, cx, |s| {
12929            s.move_heads_with(|map, head, goal| {
12930                movement::up(map, head, goal, false, text_layout_details)
12931            })
12932        })
12933    }
12934
12935    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12936        self.take_rename(true, window, cx);
12937
12938        if self.mode.is_single_line() {
12939            cx.propagate();
12940            return;
12941        }
12942
12943        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12944
12945        let text_layout_details = &self.text_layout_details(window);
12946        let selection_count = self.selections.count();
12947        let first_selection = self.selections.first_anchor();
12948
12949        self.change_selections(Default::default(), window, cx, |s| {
12950            s.move_with(|map, selection| {
12951                if !selection.is_empty() {
12952                    selection.goal = SelectionGoal::None;
12953                }
12954                let (cursor, goal) = movement::down(
12955                    map,
12956                    selection.end,
12957                    selection.goal,
12958                    false,
12959                    text_layout_details,
12960                );
12961                selection.collapse_to(cursor, goal);
12962            });
12963        });
12964
12965        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12966        {
12967            cx.propagate();
12968        }
12969    }
12970
12971    pub fn select_page_down(
12972        &mut self,
12973        _: &SelectPageDown,
12974        window: &mut Window,
12975        cx: &mut Context<Self>,
12976    ) {
12977        let Some(row_count) = self.visible_row_count() else {
12978            return;
12979        };
12980
12981        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12982
12983        let text_layout_details = &self.text_layout_details(window);
12984
12985        self.change_selections(Default::default(), window, cx, |s| {
12986            s.move_heads_with(|map, head, goal| {
12987                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12988            })
12989        })
12990    }
12991
12992    pub fn move_page_down(
12993        &mut self,
12994        action: &MovePageDown,
12995        window: &mut Window,
12996        cx: &mut Context<Self>,
12997    ) {
12998        if self.take_rename(true, window, cx).is_some() {
12999            return;
13000        }
13001
13002        if self
13003            .context_menu
13004            .borrow_mut()
13005            .as_mut()
13006            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13007            .unwrap_or(false)
13008        {
13009            return;
13010        }
13011
13012        if matches!(self.mode, EditorMode::SingleLine) {
13013            cx.propagate();
13014            return;
13015        }
13016
13017        let Some(row_count) = self.visible_row_count() else {
13018            return;
13019        };
13020
13021        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13022
13023        let effects = if action.center_cursor {
13024            SelectionEffects::scroll(Autoscroll::center())
13025        } else {
13026            SelectionEffects::default()
13027        };
13028
13029        let text_layout_details = &self.text_layout_details(window);
13030        self.change_selections(effects, window, cx, |s| {
13031            s.move_with(|map, selection| {
13032                if !selection.is_empty() {
13033                    selection.goal = SelectionGoal::None;
13034                }
13035                let (cursor, goal) = movement::down_by_rows(
13036                    map,
13037                    selection.end,
13038                    row_count,
13039                    selection.goal,
13040                    false,
13041                    text_layout_details,
13042                );
13043                selection.collapse_to(cursor, goal);
13044            });
13045        });
13046    }
13047
13048    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13049        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13050        let text_layout_details = &self.text_layout_details(window);
13051        self.change_selections(Default::default(), window, cx, |s| {
13052            s.move_heads_with(|map, head, goal| {
13053                movement::down(map, head, goal, false, text_layout_details)
13054            })
13055        });
13056    }
13057
13058    pub fn context_menu_first(
13059        &mut self,
13060        _: &ContextMenuFirst,
13061        window: &mut Window,
13062        cx: &mut Context<Self>,
13063    ) {
13064        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13065            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13066        }
13067    }
13068
13069    pub fn context_menu_prev(
13070        &mut self,
13071        _: &ContextMenuPrevious,
13072        window: &mut Window,
13073        cx: &mut Context<Self>,
13074    ) {
13075        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13076            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13077        }
13078    }
13079
13080    pub fn context_menu_next(
13081        &mut self,
13082        _: &ContextMenuNext,
13083        window: &mut Window,
13084        cx: &mut Context<Self>,
13085    ) {
13086        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13087            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13088        }
13089    }
13090
13091    pub fn context_menu_last(
13092        &mut self,
13093        _: &ContextMenuLast,
13094        window: &mut Window,
13095        cx: &mut Context<Self>,
13096    ) {
13097        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13098            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13099        }
13100    }
13101
13102    pub fn signature_help_prev(
13103        &mut self,
13104        _: &SignatureHelpPrevious,
13105        _: &mut Window,
13106        cx: &mut Context<Self>,
13107    ) {
13108        if let Some(popover) = self.signature_help_state.popover_mut() {
13109            if popover.current_signature == 0 {
13110                popover.current_signature = popover.signatures.len() - 1;
13111            } else {
13112                popover.current_signature -= 1;
13113            }
13114            cx.notify();
13115        }
13116    }
13117
13118    pub fn signature_help_next(
13119        &mut self,
13120        _: &SignatureHelpNext,
13121        _: &mut Window,
13122        cx: &mut Context<Self>,
13123    ) {
13124        if let Some(popover) = self.signature_help_state.popover_mut() {
13125            if popover.current_signature + 1 == popover.signatures.len() {
13126                popover.current_signature = 0;
13127            } else {
13128                popover.current_signature += 1;
13129            }
13130            cx.notify();
13131        }
13132    }
13133
13134    pub fn move_to_previous_word_start(
13135        &mut self,
13136        _: &MoveToPreviousWordStart,
13137        window: &mut Window,
13138        cx: &mut Context<Self>,
13139    ) {
13140        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13141        self.change_selections(Default::default(), window, cx, |s| {
13142            s.move_cursors_with(|map, head, _| {
13143                (
13144                    movement::previous_word_start(map, head),
13145                    SelectionGoal::None,
13146                )
13147            });
13148        })
13149    }
13150
13151    pub fn move_to_previous_subword_start(
13152        &mut self,
13153        _: &MoveToPreviousSubwordStart,
13154        window: &mut Window,
13155        cx: &mut Context<Self>,
13156    ) {
13157        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13158        self.change_selections(Default::default(), window, cx, |s| {
13159            s.move_cursors_with(|map, head, _| {
13160                (
13161                    movement::previous_subword_start(map, head),
13162                    SelectionGoal::None,
13163                )
13164            });
13165        })
13166    }
13167
13168    pub fn select_to_previous_word_start(
13169        &mut self,
13170        _: &SelectToPreviousWordStart,
13171        window: &mut Window,
13172        cx: &mut Context<Self>,
13173    ) {
13174        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13175        self.change_selections(Default::default(), window, cx, |s| {
13176            s.move_heads_with(|map, head, _| {
13177                (
13178                    movement::previous_word_start(map, head),
13179                    SelectionGoal::None,
13180                )
13181            });
13182        })
13183    }
13184
13185    pub fn select_to_previous_subword_start(
13186        &mut self,
13187        _: &SelectToPreviousSubwordStart,
13188        window: &mut Window,
13189        cx: &mut Context<Self>,
13190    ) {
13191        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13192        self.change_selections(Default::default(), window, cx, |s| {
13193            s.move_heads_with(|map, head, _| {
13194                (
13195                    movement::previous_subword_start(map, head),
13196                    SelectionGoal::None,
13197                )
13198            });
13199        })
13200    }
13201
13202    pub fn delete_to_previous_word_start(
13203        &mut self,
13204        action: &DeleteToPreviousWordStart,
13205        window: &mut Window,
13206        cx: &mut Context<Self>,
13207    ) {
13208        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13209        self.transact(window, cx, |this, window, cx| {
13210            this.select_autoclose_pair(window, cx);
13211            this.change_selections(Default::default(), window, cx, |s| {
13212                s.move_with(|map, selection| {
13213                    if selection.is_empty() {
13214                        let mut cursor = if action.ignore_newlines {
13215                            movement::previous_word_start(map, selection.head())
13216                        } else {
13217                            movement::previous_word_start_or_newline(map, selection.head())
13218                        };
13219                        cursor = movement::adjust_greedy_deletion(
13220                            map,
13221                            selection.head(),
13222                            cursor,
13223                            action.ignore_brackets,
13224                        );
13225                        selection.set_head(cursor, SelectionGoal::None);
13226                    }
13227                });
13228            });
13229            this.insert("", window, cx);
13230        });
13231    }
13232
13233    pub fn delete_to_previous_subword_start(
13234        &mut self,
13235        _: &DeleteToPreviousSubwordStart,
13236        window: &mut Window,
13237        cx: &mut Context<Self>,
13238    ) {
13239        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13240        self.transact(window, cx, |this, window, cx| {
13241            this.select_autoclose_pair(window, cx);
13242            this.change_selections(Default::default(), window, cx, |s| {
13243                s.move_with(|map, selection| {
13244                    if selection.is_empty() {
13245                        let mut cursor = movement::previous_subword_start(map, selection.head());
13246                        cursor =
13247                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13248                        selection.set_head(cursor, SelectionGoal::None);
13249                    }
13250                });
13251            });
13252            this.insert("", window, cx);
13253        });
13254    }
13255
13256    pub fn move_to_next_word_end(
13257        &mut self,
13258        _: &MoveToNextWordEnd,
13259        window: &mut Window,
13260        cx: &mut Context<Self>,
13261    ) {
13262        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13263        self.change_selections(Default::default(), window, cx, |s| {
13264            s.move_cursors_with(|map, head, _| {
13265                (movement::next_word_end(map, head), SelectionGoal::None)
13266            });
13267        })
13268    }
13269
13270    pub fn move_to_next_subword_end(
13271        &mut self,
13272        _: &MoveToNextSubwordEnd,
13273        window: &mut Window,
13274        cx: &mut Context<Self>,
13275    ) {
13276        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13277        self.change_selections(Default::default(), window, cx, |s| {
13278            s.move_cursors_with(|map, head, _| {
13279                (movement::next_subword_end(map, head), SelectionGoal::None)
13280            });
13281        })
13282    }
13283
13284    pub fn select_to_next_word_end(
13285        &mut self,
13286        _: &SelectToNextWordEnd,
13287        window: &mut Window,
13288        cx: &mut Context<Self>,
13289    ) {
13290        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13291        self.change_selections(Default::default(), window, cx, |s| {
13292            s.move_heads_with(|map, head, _| {
13293                (movement::next_word_end(map, head), SelectionGoal::None)
13294            });
13295        })
13296    }
13297
13298    pub fn select_to_next_subword_end(
13299        &mut self,
13300        _: &SelectToNextSubwordEnd,
13301        window: &mut Window,
13302        cx: &mut Context<Self>,
13303    ) {
13304        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13305        self.change_selections(Default::default(), window, cx, |s| {
13306            s.move_heads_with(|map, head, _| {
13307                (movement::next_subword_end(map, head), SelectionGoal::None)
13308            });
13309        })
13310    }
13311
13312    pub fn delete_to_next_word_end(
13313        &mut self,
13314        action: &DeleteToNextWordEnd,
13315        window: &mut Window,
13316        cx: &mut Context<Self>,
13317    ) {
13318        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13319        self.transact(window, cx, |this, window, cx| {
13320            this.change_selections(Default::default(), window, cx, |s| {
13321                s.move_with(|map, selection| {
13322                    if selection.is_empty() {
13323                        let mut cursor = if action.ignore_newlines {
13324                            movement::next_word_end(map, selection.head())
13325                        } else {
13326                            movement::next_word_end_or_newline(map, selection.head())
13327                        };
13328                        cursor = movement::adjust_greedy_deletion(
13329                            map,
13330                            selection.head(),
13331                            cursor,
13332                            action.ignore_brackets,
13333                        );
13334                        selection.set_head(cursor, SelectionGoal::None);
13335                    }
13336                });
13337            });
13338            this.insert("", window, cx);
13339        });
13340    }
13341
13342    pub fn delete_to_next_subword_end(
13343        &mut self,
13344        _: &DeleteToNextSubwordEnd,
13345        window: &mut Window,
13346        cx: &mut Context<Self>,
13347    ) {
13348        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13349        self.transact(window, cx, |this, window, cx| {
13350            this.change_selections(Default::default(), window, cx, |s| {
13351                s.move_with(|map, selection| {
13352                    if selection.is_empty() {
13353                        let mut cursor = movement::next_subword_end(map, selection.head());
13354                        cursor =
13355                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13356                        selection.set_head(cursor, SelectionGoal::None);
13357                    }
13358                });
13359            });
13360            this.insert("", window, cx);
13361        });
13362    }
13363
13364    pub fn move_to_beginning_of_line(
13365        &mut self,
13366        action: &MoveToBeginningOfLine,
13367        window: &mut Window,
13368        cx: &mut Context<Self>,
13369    ) {
13370        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13371        self.change_selections(Default::default(), window, cx, |s| {
13372            s.move_cursors_with(|map, head, _| {
13373                (
13374                    movement::indented_line_beginning(
13375                        map,
13376                        head,
13377                        action.stop_at_soft_wraps,
13378                        action.stop_at_indent,
13379                    ),
13380                    SelectionGoal::None,
13381                )
13382            });
13383        })
13384    }
13385
13386    pub fn select_to_beginning_of_line(
13387        &mut self,
13388        action: &SelectToBeginningOfLine,
13389        window: &mut Window,
13390        cx: &mut Context<Self>,
13391    ) {
13392        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13393        self.change_selections(Default::default(), window, cx, |s| {
13394            s.move_heads_with(|map, head, _| {
13395                (
13396                    movement::indented_line_beginning(
13397                        map,
13398                        head,
13399                        action.stop_at_soft_wraps,
13400                        action.stop_at_indent,
13401                    ),
13402                    SelectionGoal::None,
13403                )
13404            });
13405        });
13406    }
13407
13408    pub fn delete_to_beginning_of_line(
13409        &mut self,
13410        action: &DeleteToBeginningOfLine,
13411        window: &mut Window,
13412        cx: &mut Context<Self>,
13413    ) {
13414        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13415        self.transact(window, cx, |this, window, cx| {
13416            this.change_selections(Default::default(), window, cx, |s| {
13417                s.move_with(|_, selection| {
13418                    selection.reversed = true;
13419                });
13420            });
13421
13422            this.select_to_beginning_of_line(
13423                &SelectToBeginningOfLine {
13424                    stop_at_soft_wraps: false,
13425                    stop_at_indent: action.stop_at_indent,
13426                },
13427                window,
13428                cx,
13429            );
13430            this.backspace(&Backspace, window, cx);
13431        });
13432    }
13433
13434    pub fn move_to_end_of_line(
13435        &mut self,
13436        action: &MoveToEndOfLine,
13437        window: &mut Window,
13438        cx: &mut Context<Self>,
13439    ) {
13440        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13441        self.change_selections(Default::default(), window, cx, |s| {
13442            s.move_cursors_with(|map, head, _| {
13443                (
13444                    movement::line_end(map, head, action.stop_at_soft_wraps),
13445                    SelectionGoal::None,
13446                )
13447            });
13448        })
13449    }
13450
13451    pub fn select_to_end_of_line(
13452        &mut self,
13453        action: &SelectToEndOfLine,
13454        window: &mut Window,
13455        cx: &mut Context<Self>,
13456    ) {
13457        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13458        self.change_selections(Default::default(), window, cx, |s| {
13459            s.move_heads_with(|map, head, _| {
13460                (
13461                    movement::line_end(map, head, action.stop_at_soft_wraps),
13462                    SelectionGoal::None,
13463                )
13464            });
13465        })
13466    }
13467
13468    pub fn delete_to_end_of_line(
13469        &mut self,
13470        _: &DeleteToEndOfLine,
13471        window: &mut Window,
13472        cx: &mut Context<Self>,
13473    ) {
13474        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13475        self.transact(window, cx, |this, window, cx| {
13476            this.select_to_end_of_line(
13477                &SelectToEndOfLine {
13478                    stop_at_soft_wraps: false,
13479                },
13480                window,
13481                cx,
13482            );
13483            this.delete(&Delete, window, cx);
13484        });
13485    }
13486
13487    pub fn cut_to_end_of_line(
13488        &mut self,
13489        action: &CutToEndOfLine,
13490        window: &mut Window,
13491        cx: &mut Context<Self>,
13492    ) {
13493        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13494        self.transact(window, cx, |this, window, cx| {
13495            this.select_to_end_of_line(
13496                &SelectToEndOfLine {
13497                    stop_at_soft_wraps: false,
13498                },
13499                window,
13500                cx,
13501            );
13502            if !action.stop_at_newlines {
13503                this.change_selections(Default::default(), window, cx, |s| {
13504                    s.move_with(|_, sel| {
13505                        if sel.is_empty() {
13506                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13507                        }
13508                    });
13509                });
13510            }
13511            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13512            let item = this.cut_common(false, window, cx);
13513            cx.write_to_clipboard(item);
13514        });
13515    }
13516
13517    pub fn move_to_start_of_paragraph(
13518        &mut self,
13519        _: &MoveToStartOfParagraph,
13520        window: &mut Window,
13521        cx: &mut Context<Self>,
13522    ) {
13523        if matches!(self.mode, EditorMode::SingleLine) {
13524            cx.propagate();
13525            return;
13526        }
13527        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13528        self.change_selections(Default::default(), window, cx, |s| {
13529            s.move_with(|map, selection| {
13530                selection.collapse_to(
13531                    movement::start_of_paragraph(map, selection.head(), 1),
13532                    SelectionGoal::None,
13533                )
13534            });
13535        })
13536    }
13537
13538    pub fn move_to_end_of_paragraph(
13539        &mut self,
13540        _: &MoveToEndOfParagraph,
13541        window: &mut Window,
13542        cx: &mut Context<Self>,
13543    ) {
13544        if matches!(self.mode, EditorMode::SingleLine) {
13545            cx.propagate();
13546            return;
13547        }
13548        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13549        self.change_selections(Default::default(), window, cx, |s| {
13550            s.move_with(|map, selection| {
13551                selection.collapse_to(
13552                    movement::end_of_paragraph(map, selection.head(), 1),
13553                    SelectionGoal::None,
13554                )
13555            });
13556        })
13557    }
13558
13559    pub fn select_to_start_of_paragraph(
13560        &mut self,
13561        _: &SelectToStartOfParagraph,
13562        window: &mut Window,
13563        cx: &mut Context<Self>,
13564    ) {
13565        if matches!(self.mode, EditorMode::SingleLine) {
13566            cx.propagate();
13567            return;
13568        }
13569        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13570        self.change_selections(Default::default(), window, cx, |s| {
13571            s.move_heads_with(|map, head, _| {
13572                (
13573                    movement::start_of_paragraph(map, head, 1),
13574                    SelectionGoal::None,
13575                )
13576            });
13577        })
13578    }
13579
13580    pub fn select_to_end_of_paragraph(
13581        &mut self,
13582        _: &SelectToEndOfParagraph,
13583        window: &mut Window,
13584        cx: &mut Context<Self>,
13585    ) {
13586        if matches!(self.mode, EditorMode::SingleLine) {
13587            cx.propagate();
13588            return;
13589        }
13590        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13591        self.change_selections(Default::default(), window, cx, |s| {
13592            s.move_heads_with(|map, head, _| {
13593                (
13594                    movement::end_of_paragraph(map, head, 1),
13595                    SelectionGoal::None,
13596                )
13597            });
13598        })
13599    }
13600
13601    pub fn move_to_start_of_excerpt(
13602        &mut self,
13603        _: &MoveToStartOfExcerpt,
13604        window: &mut Window,
13605        cx: &mut Context<Self>,
13606    ) {
13607        if matches!(self.mode, EditorMode::SingleLine) {
13608            cx.propagate();
13609            return;
13610        }
13611        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13612        self.change_selections(Default::default(), window, cx, |s| {
13613            s.move_with(|map, selection| {
13614                selection.collapse_to(
13615                    movement::start_of_excerpt(
13616                        map,
13617                        selection.head(),
13618                        workspace::searchable::Direction::Prev,
13619                    ),
13620                    SelectionGoal::None,
13621                )
13622            });
13623        })
13624    }
13625
13626    pub fn move_to_start_of_next_excerpt(
13627        &mut self,
13628        _: &MoveToStartOfNextExcerpt,
13629        window: &mut Window,
13630        cx: &mut Context<Self>,
13631    ) {
13632        if matches!(self.mode, EditorMode::SingleLine) {
13633            cx.propagate();
13634            return;
13635        }
13636
13637        self.change_selections(Default::default(), window, cx, |s| {
13638            s.move_with(|map, selection| {
13639                selection.collapse_to(
13640                    movement::start_of_excerpt(
13641                        map,
13642                        selection.head(),
13643                        workspace::searchable::Direction::Next,
13644                    ),
13645                    SelectionGoal::None,
13646                )
13647            });
13648        })
13649    }
13650
13651    pub fn move_to_end_of_excerpt(
13652        &mut self,
13653        _: &MoveToEndOfExcerpt,
13654        window: &mut Window,
13655        cx: &mut Context<Self>,
13656    ) {
13657        if matches!(self.mode, EditorMode::SingleLine) {
13658            cx.propagate();
13659            return;
13660        }
13661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13662        self.change_selections(Default::default(), window, cx, |s| {
13663            s.move_with(|map, selection| {
13664                selection.collapse_to(
13665                    movement::end_of_excerpt(
13666                        map,
13667                        selection.head(),
13668                        workspace::searchable::Direction::Next,
13669                    ),
13670                    SelectionGoal::None,
13671                )
13672            });
13673        })
13674    }
13675
13676    pub fn move_to_end_of_previous_excerpt(
13677        &mut self,
13678        _: &MoveToEndOfPreviousExcerpt,
13679        window: &mut Window,
13680        cx: &mut Context<Self>,
13681    ) {
13682        if matches!(self.mode, EditorMode::SingleLine) {
13683            cx.propagate();
13684            return;
13685        }
13686        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13687        self.change_selections(Default::default(), window, cx, |s| {
13688            s.move_with(|map, selection| {
13689                selection.collapse_to(
13690                    movement::end_of_excerpt(
13691                        map,
13692                        selection.head(),
13693                        workspace::searchable::Direction::Prev,
13694                    ),
13695                    SelectionGoal::None,
13696                )
13697            });
13698        })
13699    }
13700
13701    pub fn select_to_start_of_excerpt(
13702        &mut self,
13703        _: &SelectToStartOfExcerpt,
13704        window: &mut Window,
13705        cx: &mut Context<Self>,
13706    ) {
13707        if matches!(self.mode, EditorMode::SingleLine) {
13708            cx.propagate();
13709            return;
13710        }
13711        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13712        self.change_selections(Default::default(), window, cx, |s| {
13713            s.move_heads_with(|map, head, _| {
13714                (
13715                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13716                    SelectionGoal::None,
13717                )
13718            });
13719        })
13720    }
13721
13722    pub fn select_to_start_of_next_excerpt(
13723        &mut self,
13724        _: &SelectToStartOfNextExcerpt,
13725        window: &mut Window,
13726        cx: &mut Context<Self>,
13727    ) {
13728        if matches!(self.mode, EditorMode::SingleLine) {
13729            cx.propagate();
13730            return;
13731        }
13732        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13733        self.change_selections(Default::default(), window, cx, |s| {
13734            s.move_heads_with(|map, head, _| {
13735                (
13736                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13737                    SelectionGoal::None,
13738                )
13739            });
13740        })
13741    }
13742
13743    pub fn select_to_end_of_excerpt(
13744        &mut self,
13745        _: &SelectToEndOfExcerpt,
13746        window: &mut Window,
13747        cx: &mut Context<Self>,
13748    ) {
13749        if matches!(self.mode, EditorMode::SingleLine) {
13750            cx.propagate();
13751            return;
13752        }
13753        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13754        self.change_selections(Default::default(), window, cx, |s| {
13755            s.move_heads_with(|map, head, _| {
13756                (
13757                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13758                    SelectionGoal::None,
13759                )
13760            });
13761        })
13762    }
13763
13764    pub fn select_to_end_of_previous_excerpt(
13765        &mut self,
13766        _: &SelectToEndOfPreviousExcerpt,
13767        window: &mut Window,
13768        cx: &mut Context<Self>,
13769    ) {
13770        if matches!(self.mode, EditorMode::SingleLine) {
13771            cx.propagate();
13772            return;
13773        }
13774        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13775        self.change_selections(Default::default(), window, cx, |s| {
13776            s.move_heads_with(|map, head, _| {
13777                (
13778                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13779                    SelectionGoal::None,
13780                )
13781            });
13782        })
13783    }
13784
13785    pub fn move_to_beginning(
13786        &mut self,
13787        _: &MoveToBeginning,
13788        window: &mut Window,
13789        cx: &mut Context<Self>,
13790    ) {
13791        if matches!(self.mode, EditorMode::SingleLine) {
13792            cx.propagate();
13793            return;
13794        }
13795        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13796        self.change_selections(Default::default(), window, cx, |s| {
13797            s.select_ranges(vec![0..0]);
13798        });
13799    }
13800
13801    pub fn select_to_beginning(
13802        &mut self,
13803        _: &SelectToBeginning,
13804        window: &mut Window,
13805        cx: &mut Context<Self>,
13806    ) {
13807        let mut selection = self.selections.last::<Point>(cx);
13808        selection.set_head(Point::zero(), SelectionGoal::None);
13809        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13810        self.change_selections(Default::default(), window, cx, |s| {
13811            s.select(vec![selection]);
13812        });
13813    }
13814
13815    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13816        if matches!(self.mode, EditorMode::SingleLine) {
13817            cx.propagate();
13818            return;
13819        }
13820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13821        let cursor = self.buffer.read(cx).read(cx).len();
13822        self.change_selections(Default::default(), window, cx, |s| {
13823            s.select_ranges(vec![cursor..cursor])
13824        });
13825    }
13826
13827    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13828        self.nav_history = nav_history;
13829    }
13830
13831    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13832        self.nav_history.as_ref()
13833    }
13834
13835    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13836        self.push_to_nav_history(
13837            self.selections.newest_anchor().head(),
13838            None,
13839            false,
13840            true,
13841            cx,
13842        );
13843    }
13844
13845    fn push_to_nav_history(
13846        &mut self,
13847        cursor_anchor: Anchor,
13848        new_position: Option<Point>,
13849        is_deactivate: bool,
13850        always: bool,
13851        cx: &mut Context<Self>,
13852    ) {
13853        if let Some(nav_history) = self.nav_history.as_mut() {
13854            let buffer = self.buffer.read(cx).read(cx);
13855            let cursor_position = cursor_anchor.to_point(&buffer);
13856            let scroll_state = self.scroll_manager.anchor();
13857            let scroll_top_row = scroll_state.top_row(&buffer);
13858            drop(buffer);
13859
13860            if let Some(new_position) = new_position {
13861                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13862                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13863                    return;
13864                }
13865            }
13866
13867            nav_history.push(
13868                Some(NavigationData {
13869                    cursor_anchor,
13870                    cursor_position,
13871                    scroll_anchor: scroll_state,
13872                    scroll_top_row,
13873                }),
13874                cx,
13875            );
13876            cx.emit(EditorEvent::PushedToNavHistory {
13877                anchor: cursor_anchor,
13878                is_deactivate,
13879            })
13880        }
13881    }
13882
13883    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13884        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13885        let buffer = self.buffer.read(cx).snapshot(cx);
13886        let mut selection = self.selections.first::<usize>(cx);
13887        selection.set_head(buffer.len(), SelectionGoal::None);
13888        self.change_selections(Default::default(), window, cx, |s| {
13889            s.select(vec![selection]);
13890        });
13891    }
13892
13893    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13894        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13895        let end = self.buffer.read(cx).read(cx).len();
13896        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13897            s.select_ranges(vec![0..end]);
13898        });
13899    }
13900
13901    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13902        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13903        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13904        let mut selections = self.selections.all::<Point>(cx);
13905        let max_point = display_map.buffer_snapshot.max_point();
13906        for selection in &mut selections {
13907            let rows = selection.spanned_rows(true, &display_map);
13908            selection.start = Point::new(rows.start.0, 0);
13909            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13910            selection.reversed = false;
13911        }
13912        self.change_selections(Default::default(), window, cx, |s| {
13913            s.select(selections);
13914        });
13915    }
13916
13917    pub fn split_selection_into_lines(
13918        &mut self,
13919        action: &SplitSelectionIntoLines,
13920        window: &mut Window,
13921        cx: &mut Context<Self>,
13922    ) {
13923        let selections = self
13924            .selections
13925            .all::<Point>(cx)
13926            .into_iter()
13927            .map(|selection| selection.start..selection.end)
13928            .collect::<Vec<_>>();
13929        self.unfold_ranges(&selections, true, true, cx);
13930
13931        let mut new_selection_ranges = Vec::new();
13932        {
13933            let buffer = self.buffer.read(cx).read(cx);
13934            for selection in selections {
13935                for row in selection.start.row..selection.end.row {
13936                    let line_start = Point::new(row, 0);
13937                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13938
13939                    if action.keep_selections {
13940                        // Keep the selection range for each line
13941                        let selection_start = if row == selection.start.row {
13942                            selection.start
13943                        } else {
13944                            line_start
13945                        };
13946                        new_selection_ranges.push(selection_start..line_end);
13947                    } else {
13948                        // Collapse to cursor at end of line
13949                        new_selection_ranges.push(line_end..line_end);
13950                    }
13951                }
13952
13953                let is_multiline_selection = selection.start.row != selection.end.row;
13954                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13955                // so this action feels more ergonomic when paired with other selection operations
13956                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13957                if !should_skip_last {
13958                    if action.keep_selections {
13959                        if is_multiline_selection {
13960                            let line_start = Point::new(selection.end.row, 0);
13961                            new_selection_ranges.push(line_start..selection.end);
13962                        } else {
13963                            new_selection_ranges.push(selection.start..selection.end);
13964                        }
13965                    } else {
13966                        new_selection_ranges.push(selection.end..selection.end);
13967                    }
13968                }
13969            }
13970        }
13971        self.change_selections(Default::default(), window, cx, |s| {
13972            s.select_ranges(new_selection_ranges);
13973        });
13974    }
13975
13976    pub fn add_selection_above(
13977        &mut self,
13978        _: &AddSelectionAbove,
13979        window: &mut Window,
13980        cx: &mut Context<Self>,
13981    ) {
13982        self.add_selection(true, window, cx);
13983    }
13984
13985    pub fn add_selection_below(
13986        &mut self,
13987        _: &AddSelectionBelow,
13988        window: &mut Window,
13989        cx: &mut Context<Self>,
13990    ) {
13991        self.add_selection(false, window, cx);
13992    }
13993
13994    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13995        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13996
13997        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13998        let all_selections = self.selections.all::<Point>(cx);
13999        let text_layout_details = self.text_layout_details(window);
14000
14001        let (mut columnar_selections, new_selections_to_columnarize) = {
14002            if let Some(state) = self.add_selections_state.as_ref() {
14003                let columnar_selection_ids: HashSet<_> = state
14004                    .groups
14005                    .iter()
14006                    .flat_map(|group| group.stack.iter())
14007                    .copied()
14008                    .collect();
14009
14010                all_selections
14011                    .into_iter()
14012                    .partition(|s| columnar_selection_ids.contains(&s.id))
14013            } else {
14014                (Vec::new(), all_selections)
14015            }
14016        };
14017
14018        let mut state = self
14019            .add_selections_state
14020            .take()
14021            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14022
14023        for selection in new_selections_to_columnarize {
14024            let range = selection.display_range(&display_map).sorted();
14025            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14026            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14027            let positions = start_x.min(end_x)..start_x.max(end_x);
14028            let mut stack = Vec::new();
14029            for row in range.start.row().0..=range.end.row().0 {
14030                if let Some(selection) = self.selections.build_columnar_selection(
14031                    &display_map,
14032                    DisplayRow(row),
14033                    &positions,
14034                    selection.reversed,
14035                    &text_layout_details,
14036                ) {
14037                    stack.push(selection.id);
14038                    columnar_selections.push(selection);
14039                }
14040            }
14041            if !stack.is_empty() {
14042                if above {
14043                    stack.reverse();
14044                }
14045                state.groups.push(AddSelectionsGroup { above, stack });
14046            }
14047        }
14048
14049        let mut final_selections = Vec::new();
14050        let end_row = if above {
14051            DisplayRow(0)
14052        } else {
14053            display_map.max_point().row()
14054        };
14055
14056        let mut last_added_item_per_group = HashMap::default();
14057        for group in state.groups.iter_mut() {
14058            if let Some(last_id) = group.stack.last() {
14059                last_added_item_per_group.insert(*last_id, group);
14060            }
14061        }
14062
14063        for selection in columnar_selections {
14064            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14065                if above == group.above {
14066                    let range = selection.display_range(&display_map).sorted();
14067                    debug_assert_eq!(range.start.row(), range.end.row());
14068                    let mut row = range.start.row();
14069                    let positions =
14070                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14071                            px(start)..px(end)
14072                        } else {
14073                            let start_x =
14074                                display_map.x_for_display_point(range.start, &text_layout_details);
14075                            let end_x =
14076                                display_map.x_for_display_point(range.end, &text_layout_details);
14077                            start_x.min(end_x)..start_x.max(end_x)
14078                        };
14079
14080                    let mut maybe_new_selection = None;
14081                    while row != end_row {
14082                        if above {
14083                            row.0 -= 1;
14084                        } else {
14085                            row.0 += 1;
14086                        }
14087                        if let Some(new_selection) = self.selections.build_columnar_selection(
14088                            &display_map,
14089                            row,
14090                            &positions,
14091                            selection.reversed,
14092                            &text_layout_details,
14093                        ) {
14094                            maybe_new_selection = Some(new_selection);
14095                            break;
14096                        }
14097                    }
14098
14099                    if let Some(new_selection) = maybe_new_selection {
14100                        group.stack.push(new_selection.id);
14101                        if above {
14102                            final_selections.push(new_selection);
14103                            final_selections.push(selection);
14104                        } else {
14105                            final_selections.push(selection);
14106                            final_selections.push(new_selection);
14107                        }
14108                    } else {
14109                        final_selections.push(selection);
14110                    }
14111                } else {
14112                    group.stack.pop();
14113                }
14114            } else {
14115                final_selections.push(selection);
14116            }
14117        }
14118
14119        self.change_selections(Default::default(), window, cx, |s| {
14120            s.select(final_selections);
14121        });
14122
14123        let final_selection_ids: HashSet<_> = self
14124            .selections
14125            .all::<Point>(cx)
14126            .iter()
14127            .map(|s| s.id)
14128            .collect();
14129        state.groups.retain_mut(|group| {
14130            // selections might get merged above so we remove invalid items from stacks
14131            group.stack.retain(|id| final_selection_ids.contains(id));
14132
14133            // single selection in stack can be treated as initial state
14134            group.stack.len() > 1
14135        });
14136
14137        if !state.groups.is_empty() {
14138            self.add_selections_state = Some(state);
14139        }
14140    }
14141
14142    fn select_match_ranges(
14143        &mut self,
14144        range: Range<usize>,
14145        reversed: bool,
14146        replace_newest: bool,
14147        auto_scroll: Option<Autoscroll>,
14148        window: &mut Window,
14149        cx: &mut Context<Editor>,
14150    ) {
14151        self.unfold_ranges(
14152            std::slice::from_ref(&range),
14153            false,
14154            auto_scroll.is_some(),
14155            cx,
14156        );
14157        let effects = if let Some(scroll) = auto_scroll {
14158            SelectionEffects::scroll(scroll)
14159        } else {
14160            SelectionEffects::no_scroll()
14161        };
14162        self.change_selections(effects, window, cx, |s| {
14163            if replace_newest {
14164                s.delete(s.newest_anchor().id);
14165            }
14166            if reversed {
14167                s.insert_range(range.end..range.start);
14168            } else {
14169                s.insert_range(range);
14170            }
14171        });
14172    }
14173
14174    pub fn select_next_match_internal(
14175        &mut self,
14176        display_map: &DisplaySnapshot,
14177        replace_newest: bool,
14178        autoscroll: Option<Autoscroll>,
14179        window: &mut Window,
14180        cx: &mut Context<Self>,
14181    ) -> Result<()> {
14182        let buffer = &display_map.buffer_snapshot;
14183        let mut selections = self.selections.all::<usize>(cx);
14184        if let Some(mut select_next_state) = self.select_next_state.take() {
14185            let query = &select_next_state.query;
14186            if !select_next_state.done {
14187                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14188                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14189                let mut next_selected_range = None;
14190
14191                let bytes_after_last_selection =
14192                    buffer.bytes_in_range(last_selection.end..buffer.len());
14193                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14194                let query_matches = query
14195                    .stream_find_iter(bytes_after_last_selection)
14196                    .map(|result| (last_selection.end, result))
14197                    .chain(
14198                        query
14199                            .stream_find_iter(bytes_before_first_selection)
14200                            .map(|result| (0, result)),
14201                    );
14202
14203                for (start_offset, query_match) in query_matches {
14204                    let query_match = query_match.unwrap(); // can only fail due to I/O
14205                    let offset_range =
14206                        start_offset + query_match.start()..start_offset + query_match.end();
14207
14208                    if !select_next_state.wordwise
14209                        || (!buffer.is_inside_word(offset_range.start, false)
14210                            && !buffer.is_inside_word(offset_range.end, false))
14211                    {
14212                        // TODO: This is n^2, because we might check all the selections
14213                        if !selections
14214                            .iter()
14215                            .any(|selection| selection.range().overlaps(&offset_range))
14216                        {
14217                            next_selected_range = Some(offset_range);
14218                            break;
14219                        }
14220                    }
14221                }
14222
14223                if let Some(next_selected_range) = next_selected_range {
14224                    self.select_match_ranges(
14225                        next_selected_range,
14226                        last_selection.reversed,
14227                        replace_newest,
14228                        autoscroll,
14229                        window,
14230                        cx,
14231                    );
14232                } else {
14233                    select_next_state.done = true;
14234                }
14235            }
14236
14237            self.select_next_state = Some(select_next_state);
14238        } else {
14239            let mut only_carets = true;
14240            let mut same_text_selected = true;
14241            let mut selected_text = None;
14242
14243            let mut selections_iter = selections.iter().peekable();
14244            while let Some(selection) = selections_iter.next() {
14245                if selection.start != selection.end {
14246                    only_carets = false;
14247                }
14248
14249                if same_text_selected {
14250                    if selected_text.is_none() {
14251                        selected_text =
14252                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14253                    }
14254
14255                    if let Some(next_selection) = selections_iter.peek() {
14256                        if next_selection.range().len() == selection.range().len() {
14257                            let next_selected_text = buffer
14258                                .text_for_range(next_selection.range())
14259                                .collect::<String>();
14260                            if Some(next_selected_text) != selected_text {
14261                                same_text_selected = false;
14262                                selected_text = None;
14263                            }
14264                        } else {
14265                            same_text_selected = false;
14266                            selected_text = None;
14267                        }
14268                    }
14269                }
14270            }
14271
14272            if only_carets {
14273                for selection in &mut selections {
14274                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14275                    selection.start = word_range.start;
14276                    selection.end = word_range.end;
14277                    selection.goal = SelectionGoal::None;
14278                    selection.reversed = false;
14279                    self.select_match_ranges(
14280                        selection.start..selection.end,
14281                        selection.reversed,
14282                        replace_newest,
14283                        autoscroll,
14284                        window,
14285                        cx,
14286                    );
14287                }
14288
14289                if selections.len() == 1 {
14290                    let selection = selections
14291                        .last()
14292                        .expect("ensured that there's only one selection");
14293                    let query = buffer
14294                        .text_for_range(selection.start..selection.end)
14295                        .collect::<String>();
14296                    let is_empty = query.is_empty();
14297                    let select_state = SelectNextState {
14298                        query: AhoCorasick::new(&[query])?,
14299                        wordwise: true,
14300                        done: is_empty,
14301                    };
14302                    self.select_next_state = Some(select_state);
14303                } else {
14304                    self.select_next_state = None;
14305                }
14306            } else if let Some(selected_text) = selected_text {
14307                self.select_next_state = Some(SelectNextState {
14308                    query: AhoCorasick::new(&[selected_text])?,
14309                    wordwise: false,
14310                    done: false,
14311                });
14312                self.select_next_match_internal(
14313                    display_map,
14314                    replace_newest,
14315                    autoscroll,
14316                    window,
14317                    cx,
14318                )?;
14319            }
14320        }
14321        Ok(())
14322    }
14323
14324    pub fn select_all_matches(
14325        &mut self,
14326        _action: &SelectAllMatches,
14327        window: &mut Window,
14328        cx: &mut Context<Self>,
14329    ) -> Result<()> {
14330        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14331
14332        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14333
14334        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14335        let Some(select_next_state) = self.select_next_state.as_mut() else {
14336            return Ok(());
14337        };
14338        if select_next_state.done {
14339            return Ok(());
14340        }
14341
14342        let mut new_selections = Vec::new();
14343
14344        let reversed = self.selections.oldest::<usize>(cx).reversed;
14345        let buffer = &display_map.buffer_snapshot;
14346        let query_matches = select_next_state
14347            .query
14348            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14349
14350        for query_match in query_matches.into_iter() {
14351            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14352            let offset_range = if reversed {
14353                query_match.end()..query_match.start()
14354            } else {
14355                query_match.start()..query_match.end()
14356            };
14357
14358            if !select_next_state.wordwise
14359                || (!buffer.is_inside_word(offset_range.start, false)
14360                    && !buffer.is_inside_word(offset_range.end, false))
14361            {
14362                new_selections.push(offset_range.start..offset_range.end);
14363            }
14364        }
14365
14366        select_next_state.done = true;
14367
14368        if new_selections.is_empty() {
14369            log::error!("bug: new_selections is empty in select_all_matches");
14370            return Ok(());
14371        }
14372
14373        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14374        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14375            selections.select_ranges(new_selections)
14376        });
14377
14378        Ok(())
14379    }
14380
14381    pub fn select_next(
14382        &mut self,
14383        action: &SelectNext,
14384        window: &mut Window,
14385        cx: &mut Context<Self>,
14386    ) -> Result<()> {
14387        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14388        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14389        self.select_next_match_internal(
14390            &display_map,
14391            action.replace_newest,
14392            Some(Autoscroll::newest()),
14393            window,
14394            cx,
14395        )?;
14396        Ok(())
14397    }
14398
14399    pub fn select_previous(
14400        &mut self,
14401        action: &SelectPrevious,
14402        window: &mut Window,
14403        cx: &mut Context<Self>,
14404    ) -> Result<()> {
14405        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14406        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14407        let buffer = &display_map.buffer_snapshot;
14408        let mut selections = self.selections.all::<usize>(cx);
14409        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14410            let query = &select_prev_state.query;
14411            if !select_prev_state.done {
14412                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14413                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14414                let mut next_selected_range = None;
14415                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14416                let bytes_before_last_selection =
14417                    buffer.reversed_bytes_in_range(0..last_selection.start);
14418                let bytes_after_first_selection =
14419                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14420                let query_matches = query
14421                    .stream_find_iter(bytes_before_last_selection)
14422                    .map(|result| (last_selection.start, result))
14423                    .chain(
14424                        query
14425                            .stream_find_iter(bytes_after_first_selection)
14426                            .map(|result| (buffer.len(), result)),
14427                    );
14428                for (end_offset, query_match) in query_matches {
14429                    let query_match = query_match.unwrap(); // can only fail due to I/O
14430                    let offset_range =
14431                        end_offset - query_match.end()..end_offset - query_match.start();
14432
14433                    if !select_prev_state.wordwise
14434                        || (!buffer.is_inside_word(offset_range.start, false)
14435                            && !buffer.is_inside_word(offset_range.end, false))
14436                    {
14437                        next_selected_range = Some(offset_range);
14438                        break;
14439                    }
14440                }
14441
14442                if let Some(next_selected_range) = next_selected_range {
14443                    self.select_match_ranges(
14444                        next_selected_range,
14445                        last_selection.reversed,
14446                        action.replace_newest,
14447                        Some(Autoscroll::newest()),
14448                        window,
14449                        cx,
14450                    );
14451                } else {
14452                    select_prev_state.done = true;
14453                }
14454            }
14455
14456            self.select_prev_state = Some(select_prev_state);
14457        } else {
14458            let mut only_carets = true;
14459            let mut same_text_selected = true;
14460            let mut selected_text = None;
14461
14462            let mut selections_iter = selections.iter().peekable();
14463            while let Some(selection) = selections_iter.next() {
14464                if selection.start != selection.end {
14465                    only_carets = false;
14466                }
14467
14468                if same_text_selected {
14469                    if selected_text.is_none() {
14470                        selected_text =
14471                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14472                    }
14473
14474                    if let Some(next_selection) = selections_iter.peek() {
14475                        if next_selection.range().len() == selection.range().len() {
14476                            let next_selected_text = buffer
14477                                .text_for_range(next_selection.range())
14478                                .collect::<String>();
14479                            if Some(next_selected_text) != selected_text {
14480                                same_text_selected = false;
14481                                selected_text = None;
14482                            }
14483                        } else {
14484                            same_text_selected = false;
14485                            selected_text = None;
14486                        }
14487                    }
14488                }
14489            }
14490
14491            if only_carets {
14492                for selection in &mut selections {
14493                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14494                    selection.start = word_range.start;
14495                    selection.end = word_range.end;
14496                    selection.goal = SelectionGoal::None;
14497                    selection.reversed = false;
14498                    self.select_match_ranges(
14499                        selection.start..selection.end,
14500                        selection.reversed,
14501                        action.replace_newest,
14502                        Some(Autoscroll::newest()),
14503                        window,
14504                        cx,
14505                    );
14506                }
14507                if selections.len() == 1 {
14508                    let selection = selections
14509                        .last()
14510                        .expect("ensured that there's only one selection");
14511                    let query = buffer
14512                        .text_for_range(selection.start..selection.end)
14513                        .collect::<String>();
14514                    let is_empty = query.is_empty();
14515                    let select_state = SelectNextState {
14516                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14517                        wordwise: true,
14518                        done: is_empty,
14519                    };
14520                    self.select_prev_state = Some(select_state);
14521                } else {
14522                    self.select_prev_state = None;
14523                }
14524            } else if let Some(selected_text) = selected_text {
14525                self.select_prev_state = Some(SelectNextState {
14526                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14527                    wordwise: false,
14528                    done: false,
14529                });
14530                self.select_previous(action, window, cx)?;
14531            }
14532        }
14533        Ok(())
14534    }
14535
14536    pub fn find_next_match(
14537        &mut self,
14538        _: &FindNextMatch,
14539        window: &mut Window,
14540        cx: &mut Context<Self>,
14541    ) -> Result<()> {
14542        let selections = self.selections.disjoint_anchors_arc();
14543        match selections.first() {
14544            Some(first) if selections.len() >= 2 => {
14545                self.change_selections(Default::default(), window, cx, |s| {
14546                    s.select_ranges([first.range()]);
14547                });
14548            }
14549            _ => self.select_next(
14550                &SelectNext {
14551                    replace_newest: true,
14552                },
14553                window,
14554                cx,
14555            )?,
14556        }
14557        Ok(())
14558    }
14559
14560    pub fn find_previous_match(
14561        &mut self,
14562        _: &FindPreviousMatch,
14563        window: &mut Window,
14564        cx: &mut Context<Self>,
14565    ) -> Result<()> {
14566        let selections = self.selections.disjoint_anchors_arc();
14567        match selections.last() {
14568            Some(last) if selections.len() >= 2 => {
14569                self.change_selections(Default::default(), window, cx, |s| {
14570                    s.select_ranges([last.range()]);
14571                });
14572            }
14573            _ => self.select_previous(
14574                &SelectPrevious {
14575                    replace_newest: true,
14576                },
14577                window,
14578                cx,
14579            )?,
14580        }
14581        Ok(())
14582    }
14583
14584    pub fn toggle_comments(
14585        &mut self,
14586        action: &ToggleComments,
14587        window: &mut Window,
14588        cx: &mut Context<Self>,
14589    ) {
14590        if self.read_only(cx) {
14591            return;
14592        }
14593        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14594        let text_layout_details = &self.text_layout_details(window);
14595        self.transact(window, cx, |this, window, cx| {
14596            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14597            let mut edits = Vec::new();
14598            let mut selection_edit_ranges = Vec::new();
14599            let mut last_toggled_row = None;
14600            let snapshot = this.buffer.read(cx).read(cx);
14601            let empty_str: Arc<str> = Arc::default();
14602            let mut suffixes_inserted = Vec::new();
14603            let ignore_indent = action.ignore_indent;
14604
14605            fn comment_prefix_range(
14606                snapshot: &MultiBufferSnapshot,
14607                row: MultiBufferRow,
14608                comment_prefix: &str,
14609                comment_prefix_whitespace: &str,
14610                ignore_indent: bool,
14611            ) -> Range<Point> {
14612                let indent_size = if ignore_indent {
14613                    0
14614                } else {
14615                    snapshot.indent_size_for_line(row).len
14616                };
14617
14618                let start = Point::new(row.0, indent_size);
14619
14620                let mut line_bytes = snapshot
14621                    .bytes_in_range(start..snapshot.max_point())
14622                    .flatten()
14623                    .copied();
14624
14625                // If this line currently begins with the line comment prefix, then record
14626                // the range containing the prefix.
14627                if line_bytes
14628                    .by_ref()
14629                    .take(comment_prefix.len())
14630                    .eq(comment_prefix.bytes())
14631                {
14632                    // Include any whitespace that matches the comment prefix.
14633                    let matching_whitespace_len = line_bytes
14634                        .zip(comment_prefix_whitespace.bytes())
14635                        .take_while(|(a, b)| a == b)
14636                        .count() as u32;
14637                    let end = Point::new(
14638                        start.row,
14639                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14640                    );
14641                    start..end
14642                } else {
14643                    start..start
14644                }
14645            }
14646
14647            fn comment_suffix_range(
14648                snapshot: &MultiBufferSnapshot,
14649                row: MultiBufferRow,
14650                comment_suffix: &str,
14651                comment_suffix_has_leading_space: bool,
14652            ) -> Range<Point> {
14653                let end = Point::new(row.0, snapshot.line_len(row));
14654                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14655
14656                let mut line_end_bytes = snapshot
14657                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14658                    .flatten()
14659                    .copied();
14660
14661                let leading_space_len = if suffix_start_column > 0
14662                    && line_end_bytes.next() == Some(b' ')
14663                    && comment_suffix_has_leading_space
14664                {
14665                    1
14666                } else {
14667                    0
14668                };
14669
14670                // If this line currently begins with the line comment prefix, then record
14671                // the range containing the prefix.
14672                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14673                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14674                    start..end
14675                } else {
14676                    end..end
14677                }
14678            }
14679
14680            // TODO: Handle selections that cross excerpts
14681            for selection in &mut selections {
14682                let start_column = snapshot
14683                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14684                    .len;
14685                let language = if let Some(language) =
14686                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14687                {
14688                    language
14689                } else {
14690                    continue;
14691                };
14692
14693                selection_edit_ranges.clear();
14694
14695                // If multiple selections contain a given row, avoid processing that
14696                // row more than once.
14697                let mut start_row = MultiBufferRow(selection.start.row);
14698                if last_toggled_row == Some(start_row) {
14699                    start_row = start_row.next_row();
14700                }
14701                let end_row =
14702                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14703                        MultiBufferRow(selection.end.row - 1)
14704                    } else {
14705                        MultiBufferRow(selection.end.row)
14706                    };
14707                last_toggled_row = Some(end_row);
14708
14709                if start_row > end_row {
14710                    continue;
14711                }
14712
14713                // If the language has line comments, toggle those.
14714                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14715
14716                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14717                if ignore_indent {
14718                    full_comment_prefixes = full_comment_prefixes
14719                        .into_iter()
14720                        .map(|s| Arc::from(s.trim_end()))
14721                        .collect();
14722                }
14723
14724                if !full_comment_prefixes.is_empty() {
14725                    let first_prefix = full_comment_prefixes
14726                        .first()
14727                        .expect("prefixes is non-empty");
14728                    let prefix_trimmed_lengths = full_comment_prefixes
14729                        .iter()
14730                        .map(|p| p.trim_end_matches(' ').len())
14731                        .collect::<SmallVec<[usize; 4]>>();
14732
14733                    let mut all_selection_lines_are_comments = true;
14734
14735                    for row in start_row.0..=end_row.0 {
14736                        let row = MultiBufferRow(row);
14737                        if start_row < end_row && snapshot.is_line_blank(row) {
14738                            continue;
14739                        }
14740
14741                        let prefix_range = full_comment_prefixes
14742                            .iter()
14743                            .zip(prefix_trimmed_lengths.iter().copied())
14744                            .map(|(prefix, trimmed_prefix_len)| {
14745                                comment_prefix_range(
14746                                    snapshot.deref(),
14747                                    row,
14748                                    &prefix[..trimmed_prefix_len],
14749                                    &prefix[trimmed_prefix_len..],
14750                                    ignore_indent,
14751                                )
14752                            })
14753                            .max_by_key(|range| range.end.column - range.start.column)
14754                            .expect("prefixes is non-empty");
14755
14756                        if prefix_range.is_empty() {
14757                            all_selection_lines_are_comments = false;
14758                        }
14759
14760                        selection_edit_ranges.push(prefix_range);
14761                    }
14762
14763                    if all_selection_lines_are_comments {
14764                        edits.extend(
14765                            selection_edit_ranges
14766                                .iter()
14767                                .cloned()
14768                                .map(|range| (range, empty_str.clone())),
14769                        );
14770                    } else {
14771                        let min_column = selection_edit_ranges
14772                            .iter()
14773                            .map(|range| range.start.column)
14774                            .min()
14775                            .unwrap_or(0);
14776                        edits.extend(selection_edit_ranges.iter().map(|range| {
14777                            let position = Point::new(range.start.row, min_column);
14778                            (position..position, first_prefix.clone())
14779                        }));
14780                    }
14781                } else if let Some(BlockCommentConfig {
14782                    start: full_comment_prefix,
14783                    end: comment_suffix,
14784                    ..
14785                }) = language.block_comment()
14786                {
14787                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14788                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14789                    let prefix_range = comment_prefix_range(
14790                        snapshot.deref(),
14791                        start_row,
14792                        comment_prefix,
14793                        comment_prefix_whitespace,
14794                        ignore_indent,
14795                    );
14796                    let suffix_range = comment_suffix_range(
14797                        snapshot.deref(),
14798                        end_row,
14799                        comment_suffix.trim_start_matches(' '),
14800                        comment_suffix.starts_with(' '),
14801                    );
14802
14803                    if prefix_range.is_empty() || suffix_range.is_empty() {
14804                        edits.push((
14805                            prefix_range.start..prefix_range.start,
14806                            full_comment_prefix.clone(),
14807                        ));
14808                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14809                        suffixes_inserted.push((end_row, comment_suffix.len()));
14810                    } else {
14811                        edits.push((prefix_range, empty_str.clone()));
14812                        edits.push((suffix_range, empty_str.clone()));
14813                    }
14814                } else {
14815                    continue;
14816                }
14817            }
14818
14819            drop(snapshot);
14820            this.buffer.update(cx, |buffer, cx| {
14821                buffer.edit(edits, None, cx);
14822            });
14823
14824            // Adjust selections so that they end before any comment suffixes that
14825            // were inserted.
14826            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14827            let mut selections = this.selections.all::<Point>(cx);
14828            let snapshot = this.buffer.read(cx).read(cx);
14829            for selection in &mut selections {
14830                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14831                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14832                        Ordering::Less => {
14833                            suffixes_inserted.next();
14834                            continue;
14835                        }
14836                        Ordering::Greater => break,
14837                        Ordering::Equal => {
14838                            if selection.end.column == snapshot.line_len(row) {
14839                                if selection.is_empty() {
14840                                    selection.start.column -= suffix_len as u32;
14841                                }
14842                                selection.end.column -= suffix_len as u32;
14843                            }
14844                            break;
14845                        }
14846                    }
14847                }
14848            }
14849
14850            drop(snapshot);
14851            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14852
14853            let selections = this.selections.all::<Point>(cx);
14854            let selections_on_single_row = selections.windows(2).all(|selections| {
14855                selections[0].start.row == selections[1].start.row
14856                    && selections[0].end.row == selections[1].end.row
14857                    && selections[0].start.row == selections[0].end.row
14858            });
14859            let selections_selecting = selections
14860                .iter()
14861                .any(|selection| selection.start != selection.end);
14862            let advance_downwards = action.advance_downwards
14863                && selections_on_single_row
14864                && !selections_selecting
14865                && !matches!(this.mode, EditorMode::SingleLine);
14866
14867            if advance_downwards {
14868                let snapshot = this.buffer.read(cx).snapshot(cx);
14869
14870                this.change_selections(Default::default(), window, cx, |s| {
14871                    s.move_cursors_with(|display_snapshot, display_point, _| {
14872                        let mut point = display_point.to_point(display_snapshot);
14873                        point.row += 1;
14874                        point = snapshot.clip_point(point, Bias::Left);
14875                        let display_point = point.to_display_point(display_snapshot);
14876                        let goal = SelectionGoal::HorizontalPosition(
14877                            display_snapshot
14878                                .x_for_display_point(display_point, text_layout_details)
14879                                .into(),
14880                        );
14881                        (display_point, goal)
14882                    })
14883                });
14884            }
14885        });
14886    }
14887
14888    pub fn select_enclosing_symbol(
14889        &mut self,
14890        _: &SelectEnclosingSymbol,
14891        window: &mut Window,
14892        cx: &mut Context<Self>,
14893    ) {
14894        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14895
14896        let buffer = self.buffer.read(cx).snapshot(cx);
14897        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14898
14899        fn update_selection(
14900            selection: &Selection<usize>,
14901            buffer_snap: &MultiBufferSnapshot,
14902        ) -> Option<Selection<usize>> {
14903            let cursor = selection.head();
14904            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14905            for symbol in symbols.iter().rev() {
14906                let start = symbol.range.start.to_offset(buffer_snap);
14907                let end = symbol.range.end.to_offset(buffer_snap);
14908                let new_range = start..end;
14909                if start < selection.start || end > selection.end {
14910                    return Some(Selection {
14911                        id: selection.id,
14912                        start: new_range.start,
14913                        end: new_range.end,
14914                        goal: SelectionGoal::None,
14915                        reversed: selection.reversed,
14916                    });
14917                }
14918            }
14919            None
14920        }
14921
14922        let mut selected_larger_symbol = false;
14923        let new_selections = old_selections
14924            .iter()
14925            .map(|selection| match update_selection(selection, &buffer) {
14926                Some(new_selection) => {
14927                    if new_selection.range() != selection.range() {
14928                        selected_larger_symbol = true;
14929                    }
14930                    new_selection
14931                }
14932                None => selection.clone(),
14933            })
14934            .collect::<Vec<_>>();
14935
14936        if selected_larger_symbol {
14937            self.change_selections(Default::default(), window, cx, |s| {
14938                s.select(new_selections);
14939            });
14940        }
14941    }
14942
14943    pub fn select_larger_syntax_node(
14944        &mut self,
14945        _: &SelectLargerSyntaxNode,
14946        window: &mut Window,
14947        cx: &mut Context<Self>,
14948    ) {
14949        let Some(visible_row_count) = self.visible_row_count() else {
14950            return;
14951        };
14952        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14953        if old_selections.is_empty() {
14954            return;
14955        }
14956
14957        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14958
14959        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14960        let buffer = self.buffer.read(cx).snapshot(cx);
14961
14962        let mut selected_larger_node = false;
14963        let mut new_selections = old_selections
14964            .iter()
14965            .map(|selection| {
14966                let old_range = selection.start..selection.end;
14967
14968                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14969                    // manually select word at selection
14970                    if ["string_content", "inline"].contains(&node.kind()) {
14971                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14972                        // ignore if word is already selected
14973                        if !word_range.is_empty() && old_range != word_range {
14974                            let (last_word_range, _) =
14975                                buffer.surrounding_word(old_range.end, false);
14976                            // only select word if start and end point belongs to same word
14977                            if word_range == last_word_range {
14978                                selected_larger_node = true;
14979                                return Selection {
14980                                    id: selection.id,
14981                                    start: word_range.start,
14982                                    end: word_range.end,
14983                                    goal: SelectionGoal::None,
14984                                    reversed: selection.reversed,
14985                                };
14986                            }
14987                        }
14988                    }
14989                }
14990
14991                let mut new_range = old_range.clone();
14992                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
14993                {
14994                    new_range = match containing_range {
14995                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14996                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14997                    };
14998                    if !node.is_named() {
14999                        continue;
15000                    }
15001                    if !display_map.intersects_fold(new_range.start)
15002                        && !display_map.intersects_fold(new_range.end)
15003                    {
15004                        break;
15005                    }
15006                }
15007
15008                selected_larger_node |= new_range != old_range;
15009                Selection {
15010                    id: selection.id,
15011                    start: new_range.start,
15012                    end: new_range.end,
15013                    goal: SelectionGoal::None,
15014                    reversed: selection.reversed,
15015                }
15016            })
15017            .collect::<Vec<_>>();
15018
15019        if !selected_larger_node {
15020            return; // don't put this call in the history
15021        }
15022
15023        // scroll based on transformation done to the last selection created by the user
15024        let (last_old, last_new) = old_selections
15025            .last()
15026            .zip(new_selections.last().cloned())
15027            .expect("old_selections isn't empty");
15028
15029        // revert selection
15030        let is_selection_reversed = {
15031            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15032            new_selections.last_mut().expect("checked above").reversed =
15033                should_newest_selection_be_reversed;
15034            should_newest_selection_be_reversed
15035        };
15036
15037        if selected_larger_node {
15038            self.select_syntax_node_history.disable_clearing = true;
15039            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15040                s.select(new_selections.clone());
15041            });
15042            self.select_syntax_node_history.disable_clearing = false;
15043        }
15044
15045        let start_row = last_new.start.to_display_point(&display_map).row().0;
15046        let end_row = last_new.end.to_display_point(&display_map).row().0;
15047        let selection_height = end_row - start_row + 1;
15048        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15049
15050        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15051        let scroll_behavior = if fits_on_the_screen {
15052            self.request_autoscroll(Autoscroll::fit(), cx);
15053            SelectSyntaxNodeScrollBehavior::FitSelection
15054        } else if is_selection_reversed {
15055            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15056            SelectSyntaxNodeScrollBehavior::CursorTop
15057        } else {
15058            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15059            SelectSyntaxNodeScrollBehavior::CursorBottom
15060        };
15061
15062        self.select_syntax_node_history.push((
15063            old_selections,
15064            scroll_behavior,
15065            is_selection_reversed,
15066        ));
15067    }
15068
15069    pub fn select_smaller_syntax_node(
15070        &mut self,
15071        _: &SelectSmallerSyntaxNode,
15072        window: &mut Window,
15073        cx: &mut Context<Self>,
15074    ) {
15075        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15076
15077        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15078            self.select_syntax_node_history.pop()
15079        {
15080            if let Some(selection) = selections.last_mut() {
15081                selection.reversed = is_selection_reversed;
15082            }
15083
15084            self.select_syntax_node_history.disable_clearing = true;
15085            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15086                s.select(selections.to_vec());
15087            });
15088            self.select_syntax_node_history.disable_clearing = false;
15089
15090            match scroll_behavior {
15091                SelectSyntaxNodeScrollBehavior::CursorTop => {
15092                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15093                }
15094                SelectSyntaxNodeScrollBehavior::FitSelection => {
15095                    self.request_autoscroll(Autoscroll::fit(), cx);
15096                }
15097                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15098                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15099                }
15100            }
15101        }
15102    }
15103
15104    pub fn unwrap_syntax_node(
15105        &mut self,
15106        _: &UnwrapSyntaxNode,
15107        window: &mut Window,
15108        cx: &mut Context<Self>,
15109    ) {
15110        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15111
15112        let buffer = self.buffer.read(cx).snapshot(cx);
15113        let selections = self
15114            .selections
15115            .all::<usize>(cx)
15116            .into_iter()
15117            // subtracting the offset requires sorting
15118            .sorted_by_key(|i| i.start);
15119
15120        let full_edits = selections
15121            .into_iter()
15122            .filter_map(|selection| {
15123                let child = if selection.is_empty()
15124                    && let Some((_, ancestor_range)) =
15125                        buffer.syntax_ancestor(selection.start..selection.end)
15126                {
15127                    match ancestor_range {
15128                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15129                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15130                    }
15131                } else {
15132                    selection.range()
15133                };
15134
15135                let mut parent = child.clone();
15136                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15137                    parent = match ancestor_range {
15138                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15139                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15140                    };
15141                    if parent.start < child.start || parent.end > child.end {
15142                        break;
15143                    }
15144                }
15145
15146                if parent == child {
15147                    return None;
15148                }
15149                let text = buffer.text_for_range(child).collect::<String>();
15150                Some((selection.id, parent, text))
15151            })
15152            .collect::<Vec<_>>();
15153        if full_edits.is_empty() {
15154            return;
15155        }
15156
15157        self.transact(window, cx, |this, window, cx| {
15158            this.buffer.update(cx, |buffer, cx| {
15159                buffer.edit(
15160                    full_edits
15161                        .iter()
15162                        .map(|(_, p, t)| (p.clone(), t.clone()))
15163                        .collect::<Vec<_>>(),
15164                    None,
15165                    cx,
15166                );
15167            });
15168            this.change_selections(Default::default(), window, cx, |s| {
15169                let mut offset = 0;
15170                let mut selections = vec![];
15171                for (id, parent, text) in full_edits {
15172                    let start = parent.start - offset;
15173                    offset += parent.len() - text.len();
15174                    selections.push(Selection {
15175                        id,
15176                        start,
15177                        end: start + text.len(),
15178                        reversed: false,
15179                        goal: Default::default(),
15180                    });
15181                }
15182                s.select(selections);
15183            });
15184        });
15185    }
15186
15187    pub fn select_next_syntax_node(
15188        &mut self,
15189        _: &SelectNextSyntaxNode,
15190        window: &mut Window,
15191        cx: &mut Context<Self>,
15192    ) {
15193        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15194        if old_selections.is_empty() {
15195            return;
15196        }
15197
15198        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15199
15200        let buffer = self.buffer.read(cx).snapshot(cx);
15201        let mut selected_sibling = false;
15202
15203        let new_selections = old_selections
15204            .iter()
15205            .map(|selection| {
15206                let old_range = selection.start..selection.end;
15207
15208                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15209                    let new_range = node.byte_range();
15210                    selected_sibling = true;
15211                    Selection {
15212                        id: selection.id,
15213                        start: new_range.start,
15214                        end: new_range.end,
15215                        goal: SelectionGoal::None,
15216                        reversed: selection.reversed,
15217                    }
15218                } else {
15219                    selection.clone()
15220                }
15221            })
15222            .collect::<Vec<_>>();
15223
15224        if selected_sibling {
15225            self.change_selections(
15226                SelectionEffects::scroll(Autoscroll::fit()),
15227                window,
15228                cx,
15229                |s| {
15230                    s.select(new_selections);
15231                },
15232            );
15233        }
15234    }
15235
15236    pub fn select_prev_syntax_node(
15237        &mut self,
15238        _: &SelectPreviousSyntaxNode,
15239        window: &mut Window,
15240        cx: &mut Context<Self>,
15241    ) {
15242        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15243        if old_selections.is_empty() {
15244            return;
15245        }
15246
15247        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15248
15249        let buffer = self.buffer.read(cx).snapshot(cx);
15250        let mut selected_sibling = false;
15251
15252        let new_selections = old_selections
15253            .iter()
15254            .map(|selection| {
15255                let old_range = selection.start..selection.end;
15256
15257                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15258                    let new_range = node.byte_range();
15259                    selected_sibling = true;
15260                    Selection {
15261                        id: selection.id,
15262                        start: new_range.start,
15263                        end: new_range.end,
15264                        goal: SelectionGoal::None,
15265                        reversed: selection.reversed,
15266                    }
15267                } else {
15268                    selection.clone()
15269                }
15270            })
15271            .collect::<Vec<_>>();
15272
15273        if selected_sibling {
15274            self.change_selections(
15275                SelectionEffects::scroll(Autoscroll::fit()),
15276                window,
15277                cx,
15278                |s| {
15279                    s.select(new_selections);
15280                },
15281            );
15282        }
15283    }
15284
15285    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15286        if !EditorSettings::get_global(cx).gutter.runnables {
15287            self.clear_tasks();
15288            return Task::ready(());
15289        }
15290        let project = self.project().map(Entity::downgrade);
15291        let task_sources = self.lsp_task_sources(cx);
15292        let multi_buffer = self.buffer.downgrade();
15293        cx.spawn_in(window, async move |editor, cx| {
15294            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15295            let Some(project) = project.and_then(|p| p.upgrade()) else {
15296                return;
15297            };
15298            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15299                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15300            }) else {
15301                return;
15302            };
15303
15304            let hide_runnables = project
15305                .update(cx, |project, _| project.is_via_collab())
15306                .unwrap_or(true);
15307            if hide_runnables {
15308                return;
15309            }
15310            let new_rows =
15311                cx.background_spawn({
15312                    let snapshot = display_snapshot.clone();
15313                    async move {
15314                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15315                    }
15316                })
15317                    .await;
15318            let Ok(lsp_tasks) =
15319                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15320            else {
15321                return;
15322            };
15323            let lsp_tasks = lsp_tasks.await;
15324
15325            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15326                lsp_tasks
15327                    .into_iter()
15328                    .flat_map(|(kind, tasks)| {
15329                        tasks.into_iter().filter_map(move |(location, task)| {
15330                            Some((kind.clone(), location?, task))
15331                        })
15332                    })
15333                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15334                        let buffer = location.target.buffer;
15335                        let buffer_snapshot = buffer.read(cx).snapshot();
15336                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15337                            |(excerpt_id, snapshot, _)| {
15338                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15339                                    display_snapshot
15340                                        .buffer_snapshot
15341                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15342                                } else {
15343                                    None
15344                                }
15345                            },
15346                        );
15347                        if let Some(offset) = offset {
15348                            let task_buffer_range =
15349                                location.target.range.to_point(&buffer_snapshot);
15350                            let context_buffer_range =
15351                                task_buffer_range.to_offset(&buffer_snapshot);
15352                            let context_range = BufferOffset(context_buffer_range.start)
15353                                ..BufferOffset(context_buffer_range.end);
15354
15355                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15356                                .or_insert_with(|| RunnableTasks {
15357                                    templates: Vec::new(),
15358                                    offset,
15359                                    column: task_buffer_range.start.column,
15360                                    extra_variables: HashMap::default(),
15361                                    context_range,
15362                                })
15363                                .templates
15364                                .push((kind, task.original_task().clone()));
15365                        }
15366
15367                        acc
15368                    })
15369            }) else {
15370                return;
15371            };
15372
15373            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15374                buffer.language_settings(cx).tasks.prefer_lsp
15375            }) else {
15376                return;
15377            };
15378
15379            let rows = Self::runnable_rows(
15380                project,
15381                display_snapshot,
15382                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15383                new_rows,
15384                cx.clone(),
15385            )
15386            .await;
15387            editor
15388                .update(cx, |editor, _| {
15389                    editor.clear_tasks();
15390                    for (key, mut value) in rows {
15391                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15392                            value.templates.extend(lsp_tasks.templates);
15393                        }
15394
15395                        editor.insert_tasks(key, value);
15396                    }
15397                    for (key, value) in lsp_tasks_by_rows {
15398                        editor.insert_tasks(key, value);
15399                    }
15400                })
15401                .ok();
15402        })
15403    }
15404    fn fetch_runnable_ranges(
15405        snapshot: &DisplaySnapshot,
15406        range: Range<Anchor>,
15407    ) -> Vec<language::RunnableRange> {
15408        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15409    }
15410
15411    fn runnable_rows(
15412        project: Entity<Project>,
15413        snapshot: DisplaySnapshot,
15414        prefer_lsp: bool,
15415        runnable_ranges: Vec<RunnableRange>,
15416        cx: AsyncWindowContext,
15417    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15418        cx.spawn(async move |cx| {
15419            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15420            for mut runnable in runnable_ranges {
15421                let Some(tasks) = cx
15422                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15423                    .ok()
15424                else {
15425                    continue;
15426                };
15427                let mut tasks = tasks.await;
15428
15429                if prefer_lsp {
15430                    tasks.retain(|(task_kind, _)| {
15431                        !matches!(task_kind, TaskSourceKind::Language { .. })
15432                    });
15433                }
15434                if tasks.is_empty() {
15435                    continue;
15436                }
15437
15438                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15439                let Some(row) = snapshot
15440                    .buffer_snapshot
15441                    .buffer_line_for_row(MultiBufferRow(point.row))
15442                    .map(|(_, range)| range.start.row)
15443                else {
15444                    continue;
15445                };
15446
15447                let context_range =
15448                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15449                runnable_rows.push((
15450                    (runnable.buffer_id, row),
15451                    RunnableTasks {
15452                        templates: tasks,
15453                        offset: snapshot
15454                            .buffer_snapshot
15455                            .anchor_before(runnable.run_range.start),
15456                        context_range,
15457                        column: point.column,
15458                        extra_variables: runnable.extra_captures,
15459                    },
15460                ));
15461            }
15462            runnable_rows
15463        })
15464    }
15465
15466    fn templates_with_tags(
15467        project: &Entity<Project>,
15468        runnable: &mut Runnable,
15469        cx: &mut App,
15470    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15471        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15472            let (worktree_id, file) = project
15473                .buffer_for_id(runnable.buffer, cx)
15474                .and_then(|buffer| buffer.read(cx).file())
15475                .map(|file| (file.worktree_id(cx), file.clone()))
15476                .unzip();
15477
15478            (
15479                project.task_store().read(cx).task_inventory().cloned(),
15480                worktree_id,
15481                file,
15482            )
15483        });
15484
15485        let tags = mem::take(&mut runnable.tags);
15486        let language = runnable.language.clone();
15487        cx.spawn(async move |cx| {
15488            let mut templates_with_tags = Vec::new();
15489            if let Some(inventory) = inventory {
15490                for RunnableTag(tag) in tags {
15491                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15492                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15493                    }) else {
15494                        return templates_with_tags;
15495                    };
15496                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15497                        move |(_, template)| {
15498                            template.tags.iter().any(|source_tag| source_tag == &tag)
15499                        },
15500                    ));
15501                }
15502            }
15503            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15504
15505            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15506                // Strongest source wins; if we have worktree tag binding, prefer that to
15507                // global and language bindings;
15508                // if we have a global binding, prefer that to language binding.
15509                let first_mismatch = templates_with_tags
15510                    .iter()
15511                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15512                if let Some(index) = first_mismatch {
15513                    templates_with_tags.truncate(index);
15514                }
15515            }
15516
15517            templates_with_tags
15518        })
15519    }
15520
15521    pub fn move_to_enclosing_bracket(
15522        &mut self,
15523        _: &MoveToEnclosingBracket,
15524        window: &mut Window,
15525        cx: &mut Context<Self>,
15526    ) {
15527        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15528        self.change_selections(Default::default(), window, cx, |s| {
15529            s.move_offsets_with(|snapshot, selection| {
15530                let Some(enclosing_bracket_ranges) =
15531                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15532                else {
15533                    return;
15534                };
15535
15536                let mut best_length = usize::MAX;
15537                let mut best_inside = false;
15538                let mut best_in_bracket_range = false;
15539                let mut best_destination = None;
15540                for (open, close) in enclosing_bracket_ranges {
15541                    let close = close.to_inclusive();
15542                    let length = close.end() - open.start;
15543                    let inside = selection.start >= open.end && selection.end <= *close.start();
15544                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15545                        || close.contains(&selection.head());
15546
15547                    // If best is next to a bracket and current isn't, skip
15548                    if !in_bracket_range && best_in_bracket_range {
15549                        continue;
15550                    }
15551
15552                    // Prefer smaller lengths unless best is inside and current isn't
15553                    if length > best_length && (best_inside || !inside) {
15554                        continue;
15555                    }
15556
15557                    best_length = length;
15558                    best_inside = inside;
15559                    best_in_bracket_range = in_bracket_range;
15560                    best_destination = Some(
15561                        if close.contains(&selection.start) && close.contains(&selection.end) {
15562                            if inside { open.end } else { open.start }
15563                        } else if inside {
15564                            *close.start()
15565                        } else {
15566                            *close.end()
15567                        },
15568                    );
15569                }
15570
15571                if let Some(destination) = best_destination {
15572                    selection.collapse_to(destination, SelectionGoal::None);
15573                }
15574            })
15575        });
15576    }
15577
15578    pub fn undo_selection(
15579        &mut self,
15580        _: &UndoSelection,
15581        window: &mut Window,
15582        cx: &mut Context<Self>,
15583    ) {
15584        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15585        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15586            self.selection_history.mode = SelectionHistoryMode::Undoing;
15587            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15588                this.end_selection(window, cx);
15589                this.change_selections(
15590                    SelectionEffects::scroll(Autoscroll::newest()),
15591                    window,
15592                    cx,
15593                    |s| s.select_anchors(entry.selections.to_vec()),
15594                );
15595            });
15596            self.selection_history.mode = SelectionHistoryMode::Normal;
15597
15598            self.select_next_state = entry.select_next_state;
15599            self.select_prev_state = entry.select_prev_state;
15600            self.add_selections_state = entry.add_selections_state;
15601        }
15602    }
15603
15604    pub fn redo_selection(
15605        &mut self,
15606        _: &RedoSelection,
15607        window: &mut Window,
15608        cx: &mut Context<Self>,
15609    ) {
15610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15611        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15612            self.selection_history.mode = SelectionHistoryMode::Redoing;
15613            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15614                this.end_selection(window, cx);
15615                this.change_selections(
15616                    SelectionEffects::scroll(Autoscroll::newest()),
15617                    window,
15618                    cx,
15619                    |s| s.select_anchors(entry.selections.to_vec()),
15620                );
15621            });
15622            self.selection_history.mode = SelectionHistoryMode::Normal;
15623
15624            self.select_next_state = entry.select_next_state;
15625            self.select_prev_state = entry.select_prev_state;
15626            self.add_selections_state = entry.add_selections_state;
15627        }
15628    }
15629
15630    pub fn expand_excerpts(
15631        &mut self,
15632        action: &ExpandExcerpts,
15633        _: &mut Window,
15634        cx: &mut Context<Self>,
15635    ) {
15636        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15637    }
15638
15639    pub fn expand_excerpts_down(
15640        &mut self,
15641        action: &ExpandExcerptsDown,
15642        _: &mut Window,
15643        cx: &mut Context<Self>,
15644    ) {
15645        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15646    }
15647
15648    pub fn expand_excerpts_up(
15649        &mut self,
15650        action: &ExpandExcerptsUp,
15651        _: &mut Window,
15652        cx: &mut Context<Self>,
15653    ) {
15654        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15655    }
15656
15657    pub fn expand_excerpts_for_direction(
15658        &mut self,
15659        lines: u32,
15660        direction: ExpandExcerptDirection,
15661
15662        cx: &mut Context<Self>,
15663    ) {
15664        let selections = self.selections.disjoint_anchors_arc();
15665
15666        let lines = if lines == 0 {
15667            EditorSettings::get_global(cx).expand_excerpt_lines
15668        } else {
15669            lines
15670        };
15671
15672        self.buffer.update(cx, |buffer, cx| {
15673            let snapshot = buffer.snapshot(cx);
15674            let mut excerpt_ids = selections
15675                .iter()
15676                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15677                .collect::<Vec<_>>();
15678            excerpt_ids.sort();
15679            excerpt_ids.dedup();
15680            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15681        })
15682    }
15683
15684    pub fn expand_excerpt(
15685        &mut self,
15686        excerpt: ExcerptId,
15687        direction: ExpandExcerptDirection,
15688        window: &mut Window,
15689        cx: &mut Context<Self>,
15690    ) {
15691        let current_scroll_position = self.scroll_position(cx);
15692        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15693        let mut should_scroll_up = false;
15694
15695        if direction == ExpandExcerptDirection::Down {
15696            let multi_buffer = self.buffer.read(cx);
15697            let snapshot = multi_buffer.snapshot(cx);
15698            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15699                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15700                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15701            {
15702                let buffer_snapshot = buffer.read(cx).snapshot();
15703                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15704                let last_row = buffer_snapshot.max_point().row;
15705                let lines_below = last_row.saturating_sub(excerpt_end_row);
15706                should_scroll_up = lines_below >= lines_to_expand;
15707            }
15708        }
15709
15710        self.buffer.update(cx, |buffer, cx| {
15711            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15712        });
15713
15714        if should_scroll_up {
15715            let new_scroll_position =
15716                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15717            self.set_scroll_position(new_scroll_position, window, cx);
15718        }
15719    }
15720
15721    pub fn go_to_singleton_buffer_point(
15722        &mut self,
15723        point: Point,
15724        window: &mut Window,
15725        cx: &mut Context<Self>,
15726    ) {
15727        self.go_to_singleton_buffer_range(point..point, window, cx);
15728    }
15729
15730    pub fn go_to_singleton_buffer_range(
15731        &mut self,
15732        range: Range<Point>,
15733        window: &mut Window,
15734        cx: &mut Context<Self>,
15735    ) {
15736        let multibuffer = self.buffer().read(cx);
15737        let Some(buffer) = multibuffer.as_singleton() else {
15738            return;
15739        };
15740        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15741            return;
15742        };
15743        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15744            return;
15745        };
15746        self.change_selections(
15747            SelectionEffects::default().nav_history(true),
15748            window,
15749            cx,
15750            |s| s.select_anchor_ranges([start..end]),
15751        );
15752    }
15753
15754    pub fn go_to_diagnostic(
15755        &mut self,
15756        action: &GoToDiagnostic,
15757        window: &mut Window,
15758        cx: &mut Context<Self>,
15759    ) {
15760        if !self.diagnostics_enabled() {
15761            return;
15762        }
15763        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15764        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15765    }
15766
15767    pub fn go_to_prev_diagnostic(
15768        &mut self,
15769        action: &GoToPreviousDiagnostic,
15770        window: &mut Window,
15771        cx: &mut Context<Self>,
15772    ) {
15773        if !self.diagnostics_enabled() {
15774            return;
15775        }
15776        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15777        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15778    }
15779
15780    pub fn go_to_diagnostic_impl(
15781        &mut self,
15782        direction: Direction,
15783        severity: GoToDiagnosticSeverityFilter,
15784        window: &mut Window,
15785        cx: &mut Context<Self>,
15786    ) {
15787        let buffer = self.buffer.read(cx).snapshot(cx);
15788        let selection = self.selections.newest::<usize>(cx);
15789
15790        let mut active_group_id = None;
15791        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15792            && active_group.active_range.start.to_offset(&buffer) == selection.start
15793        {
15794            active_group_id = Some(active_group.group_id);
15795        }
15796
15797        fn filtered(
15798            snapshot: EditorSnapshot,
15799            severity: GoToDiagnosticSeverityFilter,
15800            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15801        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15802            diagnostics
15803                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15804                .filter(|entry| entry.range.start != entry.range.end)
15805                .filter(|entry| !entry.diagnostic.is_unnecessary)
15806                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15807        }
15808
15809        let snapshot = self.snapshot(window, cx);
15810        let before = filtered(
15811            snapshot.clone(),
15812            severity,
15813            buffer
15814                .diagnostics_in_range(0..selection.start)
15815                .filter(|entry| entry.range.start <= selection.start),
15816        );
15817        let after = filtered(
15818            snapshot,
15819            severity,
15820            buffer
15821                .diagnostics_in_range(selection.start..buffer.len())
15822                .filter(|entry| entry.range.start >= selection.start),
15823        );
15824
15825        let mut found: Option<DiagnosticEntry<usize>> = None;
15826        if direction == Direction::Prev {
15827            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15828            {
15829                for diagnostic in prev_diagnostics.into_iter().rev() {
15830                    if diagnostic.range.start != selection.start
15831                        || active_group_id
15832                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15833                    {
15834                        found = Some(diagnostic);
15835                        break 'outer;
15836                    }
15837                }
15838            }
15839        } else {
15840            for diagnostic in after.chain(before) {
15841                if diagnostic.range.start != selection.start
15842                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15843                {
15844                    found = Some(diagnostic);
15845                    break;
15846                }
15847            }
15848        }
15849        let Some(next_diagnostic) = found else {
15850            return;
15851        };
15852
15853        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15854        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15855            return;
15856        };
15857        self.change_selections(Default::default(), window, cx, |s| {
15858            s.select_ranges(vec![
15859                next_diagnostic.range.start..next_diagnostic.range.start,
15860            ])
15861        });
15862        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15863        self.refresh_edit_prediction(false, true, window, cx);
15864    }
15865
15866    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15867        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15868        let snapshot = self.snapshot(window, cx);
15869        let selection = self.selections.newest::<Point>(cx);
15870        self.go_to_hunk_before_or_after_position(
15871            &snapshot,
15872            selection.head(),
15873            Direction::Next,
15874            window,
15875            cx,
15876        );
15877    }
15878
15879    pub fn go_to_hunk_before_or_after_position(
15880        &mut self,
15881        snapshot: &EditorSnapshot,
15882        position: Point,
15883        direction: Direction,
15884        window: &mut Window,
15885        cx: &mut Context<Editor>,
15886    ) {
15887        let row = if direction == Direction::Next {
15888            self.hunk_after_position(snapshot, position)
15889                .map(|hunk| hunk.row_range.start)
15890        } else {
15891            self.hunk_before_position(snapshot, position)
15892        };
15893
15894        if let Some(row) = row {
15895            let destination = Point::new(row.0, 0);
15896            let autoscroll = Autoscroll::center();
15897
15898            self.unfold_ranges(&[destination..destination], false, false, cx);
15899            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15900                s.select_ranges([destination..destination]);
15901            });
15902        }
15903    }
15904
15905    fn hunk_after_position(
15906        &mut self,
15907        snapshot: &EditorSnapshot,
15908        position: Point,
15909    ) -> Option<MultiBufferDiffHunk> {
15910        snapshot
15911            .buffer_snapshot
15912            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15913            .find(|hunk| hunk.row_range.start.0 > position.row)
15914            .or_else(|| {
15915                snapshot
15916                    .buffer_snapshot
15917                    .diff_hunks_in_range(Point::zero()..position)
15918                    .find(|hunk| hunk.row_range.end.0 < position.row)
15919            })
15920    }
15921
15922    fn go_to_prev_hunk(
15923        &mut self,
15924        _: &GoToPreviousHunk,
15925        window: &mut Window,
15926        cx: &mut Context<Self>,
15927    ) {
15928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15929        let snapshot = self.snapshot(window, cx);
15930        let selection = self.selections.newest::<Point>(cx);
15931        self.go_to_hunk_before_or_after_position(
15932            &snapshot,
15933            selection.head(),
15934            Direction::Prev,
15935            window,
15936            cx,
15937        );
15938    }
15939
15940    fn hunk_before_position(
15941        &mut self,
15942        snapshot: &EditorSnapshot,
15943        position: Point,
15944    ) -> Option<MultiBufferRow> {
15945        snapshot
15946            .buffer_snapshot
15947            .diff_hunk_before(position)
15948            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15949    }
15950
15951    fn go_to_next_change(
15952        &mut self,
15953        _: &GoToNextChange,
15954        window: &mut Window,
15955        cx: &mut Context<Self>,
15956    ) {
15957        if let Some(selections) = self
15958            .change_list
15959            .next_change(1, Direction::Next)
15960            .map(|s| s.to_vec())
15961        {
15962            self.change_selections(Default::default(), window, cx, |s| {
15963                let map = s.display_map();
15964                s.select_display_ranges(selections.iter().map(|a| {
15965                    let point = a.to_display_point(&map);
15966                    point..point
15967                }))
15968            })
15969        }
15970    }
15971
15972    fn go_to_previous_change(
15973        &mut self,
15974        _: &GoToPreviousChange,
15975        window: &mut Window,
15976        cx: &mut Context<Self>,
15977    ) {
15978        if let Some(selections) = self
15979            .change_list
15980            .next_change(1, Direction::Prev)
15981            .map(|s| s.to_vec())
15982        {
15983            self.change_selections(Default::default(), window, cx, |s| {
15984                let map = s.display_map();
15985                s.select_display_ranges(selections.iter().map(|a| {
15986                    let point = a.to_display_point(&map);
15987                    point..point
15988                }))
15989            })
15990        }
15991    }
15992
15993    pub fn go_to_next_document_highlight(
15994        &mut self,
15995        _: &GoToNextDocumentHighlight,
15996        window: &mut Window,
15997        cx: &mut Context<Self>,
15998    ) {
15999        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16000    }
16001
16002    pub fn go_to_prev_document_highlight(
16003        &mut self,
16004        _: &GoToPreviousDocumentHighlight,
16005        window: &mut Window,
16006        cx: &mut Context<Self>,
16007    ) {
16008        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16009    }
16010
16011    pub fn go_to_document_highlight_before_or_after_position(
16012        &mut self,
16013        direction: Direction,
16014        window: &mut Window,
16015        cx: &mut Context<Editor>,
16016    ) {
16017        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16018        let snapshot = self.snapshot(window, cx);
16019        let buffer = &snapshot.buffer_snapshot;
16020        let position = self.selections.newest::<Point>(cx).head();
16021        let anchor_position = buffer.anchor_after(position);
16022
16023        // Get all document highlights (both read and write)
16024        let mut all_highlights = Vec::new();
16025
16026        if let Some((_, read_highlights)) = self
16027            .background_highlights
16028            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16029        {
16030            all_highlights.extend(read_highlights.iter());
16031        }
16032
16033        if let Some((_, write_highlights)) = self
16034            .background_highlights
16035            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16036        {
16037            all_highlights.extend(write_highlights.iter());
16038        }
16039
16040        if all_highlights.is_empty() {
16041            return;
16042        }
16043
16044        // Sort highlights by position
16045        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16046
16047        let target_highlight = match direction {
16048            Direction::Next => {
16049                // Find the first highlight after the current position
16050                all_highlights
16051                    .iter()
16052                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16053            }
16054            Direction::Prev => {
16055                // Find the last highlight before the current position
16056                all_highlights
16057                    .iter()
16058                    .rev()
16059                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16060            }
16061        };
16062
16063        if let Some(highlight) = target_highlight {
16064            let destination = highlight.start.to_point(buffer);
16065            let autoscroll = Autoscroll::center();
16066
16067            self.unfold_ranges(&[destination..destination], false, false, cx);
16068            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16069                s.select_ranges([destination..destination]);
16070            });
16071        }
16072    }
16073
16074    fn go_to_line<T: 'static>(
16075        &mut self,
16076        position: Anchor,
16077        highlight_color: Option<Hsla>,
16078        window: &mut Window,
16079        cx: &mut Context<Self>,
16080    ) {
16081        let snapshot = self.snapshot(window, cx).display_snapshot;
16082        let position = position.to_point(&snapshot.buffer_snapshot);
16083        let start = snapshot
16084            .buffer_snapshot
16085            .clip_point(Point::new(position.row, 0), Bias::Left);
16086        let end = start + Point::new(1, 0);
16087        let start = snapshot.buffer_snapshot.anchor_before(start);
16088        let end = snapshot.buffer_snapshot.anchor_before(end);
16089
16090        self.highlight_rows::<T>(
16091            start..end,
16092            highlight_color
16093                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16094            Default::default(),
16095            cx,
16096        );
16097
16098        if self.buffer.read(cx).is_singleton() {
16099            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16100        }
16101    }
16102
16103    pub fn go_to_definition(
16104        &mut self,
16105        _: &GoToDefinition,
16106        window: &mut Window,
16107        cx: &mut Context<Self>,
16108    ) -> Task<Result<Navigated>> {
16109        let definition =
16110            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16111        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16112        cx.spawn_in(window, async move |editor, cx| {
16113            if definition.await? == Navigated::Yes {
16114                return Ok(Navigated::Yes);
16115            }
16116            match fallback_strategy {
16117                GoToDefinitionFallback::None => Ok(Navigated::No),
16118                GoToDefinitionFallback::FindAllReferences => {
16119                    match editor.update_in(cx, |editor, window, cx| {
16120                        editor.find_all_references(&FindAllReferences, window, cx)
16121                    })? {
16122                        Some(references) => references.await,
16123                        None => Ok(Navigated::No),
16124                    }
16125                }
16126            }
16127        })
16128    }
16129
16130    pub fn go_to_declaration(
16131        &mut self,
16132        _: &GoToDeclaration,
16133        window: &mut Window,
16134        cx: &mut Context<Self>,
16135    ) -> Task<Result<Navigated>> {
16136        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16137    }
16138
16139    pub fn go_to_declaration_split(
16140        &mut self,
16141        _: &GoToDeclaration,
16142        window: &mut Window,
16143        cx: &mut Context<Self>,
16144    ) -> Task<Result<Navigated>> {
16145        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16146    }
16147
16148    pub fn go_to_implementation(
16149        &mut self,
16150        _: &GoToImplementation,
16151        window: &mut Window,
16152        cx: &mut Context<Self>,
16153    ) -> Task<Result<Navigated>> {
16154        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16155    }
16156
16157    pub fn go_to_implementation_split(
16158        &mut self,
16159        _: &GoToImplementationSplit,
16160        window: &mut Window,
16161        cx: &mut Context<Self>,
16162    ) -> Task<Result<Navigated>> {
16163        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16164    }
16165
16166    pub fn go_to_type_definition(
16167        &mut self,
16168        _: &GoToTypeDefinition,
16169        window: &mut Window,
16170        cx: &mut Context<Self>,
16171    ) -> Task<Result<Navigated>> {
16172        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16173    }
16174
16175    pub fn go_to_definition_split(
16176        &mut self,
16177        _: &GoToDefinitionSplit,
16178        window: &mut Window,
16179        cx: &mut Context<Self>,
16180    ) -> Task<Result<Navigated>> {
16181        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16182    }
16183
16184    pub fn go_to_type_definition_split(
16185        &mut self,
16186        _: &GoToTypeDefinitionSplit,
16187        window: &mut Window,
16188        cx: &mut Context<Self>,
16189    ) -> Task<Result<Navigated>> {
16190        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16191    }
16192
16193    fn go_to_definition_of_kind(
16194        &mut self,
16195        kind: GotoDefinitionKind,
16196        split: bool,
16197        window: &mut Window,
16198        cx: &mut Context<Self>,
16199    ) -> Task<Result<Navigated>> {
16200        let Some(provider) = self.semantics_provider.clone() else {
16201            return Task::ready(Ok(Navigated::No));
16202        };
16203        let head = self.selections.newest::<usize>(cx).head();
16204        let buffer = self.buffer.read(cx);
16205        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16206            return Task::ready(Ok(Navigated::No));
16207        };
16208        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16209            return Task::ready(Ok(Navigated::No));
16210        };
16211
16212        cx.spawn_in(window, async move |editor, cx| {
16213            let Some(definitions) = definitions.await? else {
16214                return Ok(Navigated::No);
16215            };
16216            let navigated = editor
16217                .update_in(cx, |editor, window, cx| {
16218                    editor.navigate_to_hover_links(
16219                        Some(kind),
16220                        definitions
16221                            .into_iter()
16222                            .filter(|location| {
16223                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16224                            })
16225                            .map(HoverLink::Text)
16226                            .collect::<Vec<_>>(),
16227                        split,
16228                        window,
16229                        cx,
16230                    )
16231                })?
16232                .await?;
16233            anyhow::Ok(navigated)
16234        })
16235    }
16236
16237    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16238        let selection = self.selections.newest_anchor();
16239        let head = selection.head();
16240        let tail = selection.tail();
16241
16242        let Some((buffer, start_position)) =
16243            self.buffer.read(cx).text_anchor_for_position(head, cx)
16244        else {
16245            return;
16246        };
16247
16248        let end_position = if head != tail {
16249            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16250                return;
16251            };
16252            Some(pos)
16253        } else {
16254            None
16255        };
16256
16257        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16258            let url = if let Some(end_pos) = end_position {
16259                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16260            } else {
16261                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16262            };
16263
16264            if let Some(url) = url {
16265                editor.update(cx, |_, cx| {
16266                    cx.open_url(&url);
16267                })
16268            } else {
16269                Ok(())
16270            }
16271        });
16272
16273        url_finder.detach();
16274    }
16275
16276    pub fn open_selected_filename(
16277        &mut self,
16278        _: &OpenSelectedFilename,
16279        window: &mut Window,
16280        cx: &mut Context<Self>,
16281    ) {
16282        let Some(workspace) = self.workspace() else {
16283            return;
16284        };
16285
16286        let position = self.selections.newest_anchor().head();
16287
16288        let Some((buffer, buffer_position)) =
16289            self.buffer.read(cx).text_anchor_for_position(position, cx)
16290        else {
16291            return;
16292        };
16293
16294        let project = self.project.clone();
16295
16296        cx.spawn_in(window, async move |_, cx| {
16297            let result = find_file(&buffer, project, buffer_position, cx).await;
16298
16299            if let Some((_, path)) = result {
16300                workspace
16301                    .update_in(cx, |workspace, window, cx| {
16302                        workspace.open_resolved_path(path, window, cx)
16303                    })?
16304                    .await?;
16305            }
16306            anyhow::Ok(())
16307        })
16308        .detach();
16309    }
16310
16311    pub(crate) fn navigate_to_hover_links(
16312        &mut self,
16313        kind: Option<GotoDefinitionKind>,
16314        definitions: Vec<HoverLink>,
16315        split: bool,
16316        window: &mut Window,
16317        cx: &mut Context<Editor>,
16318    ) -> Task<Result<Navigated>> {
16319        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16320        let mut first_url_or_file = None;
16321        let definitions: Vec<_> = definitions
16322            .into_iter()
16323            .filter_map(|def| match def {
16324                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16325                HoverLink::InlayHint(lsp_location, server_id) => {
16326                    let computation =
16327                        self.compute_target_location(lsp_location, server_id, window, cx);
16328                    Some(cx.background_spawn(computation))
16329                }
16330                HoverLink::Url(url) => {
16331                    first_url_or_file = Some(Either::Left(url));
16332                    None
16333                }
16334                HoverLink::File(path) => {
16335                    first_url_or_file = Some(Either::Right(path));
16336                    None
16337                }
16338            })
16339            .collect();
16340
16341        let workspace = self.workspace();
16342
16343        cx.spawn_in(window, async move |editor, acx| {
16344            let mut locations: Vec<Location> = future::join_all(definitions)
16345                .await
16346                .into_iter()
16347                .filter_map(|location| location.transpose())
16348                .collect::<Result<_>>()
16349                .context("location tasks")?;
16350
16351            if locations.len() > 1 {
16352                let Some(workspace) = workspace else {
16353                    return Ok(Navigated::No);
16354                };
16355
16356                let tab_kind = match kind {
16357                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16358                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16359                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16360                    Some(GotoDefinitionKind::Type) => "Types",
16361                };
16362                let title = editor
16363                    .update_in(acx, |_, _, cx| {
16364                        let target = locations
16365                            .iter()
16366                            .map(|location| {
16367                                location
16368                                    .buffer
16369                                    .read(cx)
16370                                    .text_for_range(location.range.clone())
16371                                    .collect::<String>()
16372                            })
16373                            .filter(|text| !text.contains('\n'))
16374                            .unique()
16375                            .take(3)
16376                            .join(", ");
16377                        if target.is_empty() {
16378                            tab_kind.to_owned()
16379                        } else {
16380                            format!("{tab_kind} for {target}")
16381                        }
16382                    })
16383                    .context("buffer title")?;
16384
16385                let opened = workspace
16386                    .update_in(acx, |workspace, window, cx| {
16387                        Self::open_locations_in_multibuffer(
16388                            workspace,
16389                            locations,
16390                            title,
16391                            split,
16392                            MultibufferSelectionMode::First,
16393                            window,
16394                            cx,
16395                        )
16396                    })
16397                    .is_ok();
16398
16399                anyhow::Ok(Navigated::from_bool(opened))
16400            } else if locations.is_empty() {
16401                // If there is one url or file, open it directly
16402                match first_url_or_file {
16403                    Some(Either::Left(url)) => {
16404                        acx.update(|_, cx| cx.open_url(&url))?;
16405                        Ok(Navigated::Yes)
16406                    }
16407                    Some(Either::Right(path)) => {
16408                        let Some(workspace) = workspace else {
16409                            return Ok(Navigated::No);
16410                        };
16411
16412                        workspace
16413                            .update_in(acx, |workspace, window, cx| {
16414                                workspace.open_resolved_path(path, window, cx)
16415                            })?
16416                            .await?;
16417                        Ok(Navigated::Yes)
16418                    }
16419                    None => Ok(Navigated::No),
16420                }
16421            } else {
16422                let Some(workspace) = workspace else {
16423                    return Ok(Navigated::No);
16424                };
16425
16426                let target = locations.pop().unwrap();
16427                editor.update_in(acx, |editor, window, cx| {
16428                    let range = target.range.to_point(target.buffer.read(cx));
16429                    let range = editor.range_for_match(&range);
16430                    let range = collapse_multiline_range(range);
16431
16432                    if !split
16433                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16434                    {
16435                        editor.go_to_singleton_buffer_range(range, window, cx);
16436                    } else {
16437                        let pane = workspace.read(cx).active_pane().clone();
16438                        window.defer(cx, move |window, cx| {
16439                            let target_editor: Entity<Self> =
16440                                workspace.update(cx, |workspace, cx| {
16441                                    let pane = if split {
16442                                        workspace.adjacent_pane(window, cx)
16443                                    } else {
16444                                        workspace.active_pane().clone()
16445                                    };
16446
16447                                    workspace.open_project_item(
16448                                        pane,
16449                                        target.buffer.clone(),
16450                                        true,
16451                                        true,
16452                                        window,
16453                                        cx,
16454                                    )
16455                                });
16456                            target_editor.update(cx, |target_editor, cx| {
16457                                // When selecting a definition in a different buffer, disable the nav history
16458                                // to avoid creating a history entry at the previous cursor location.
16459                                pane.update(cx, |pane, _| pane.disable_history());
16460                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16461                                pane.update(cx, |pane, _| pane.enable_history());
16462                            });
16463                        });
16464                    }
16465                    Navigated::Yes
16466                })
16467            }
16468        })
16469    }
16470
16471    fn compute_target_location(
16472        &self,
16473        lsp_location: lsp::Location,
16474        server_id: LanguageServerId,
16475        window: &mut Window,
16476        cx: &mut Context<Self>,
16477    ) -> Task<anyhow::Result<Option<Location>>> {
16478        let Some(project) = self.project.clone() else {
16479            return Task::ready(Ok(None));
16480        };
16481
16482        cx.spawn_in(window, async move |editor, cx| {
16483            let location_task = editor.update(cx, |_, cx| {
16484                project.update(cx, |project, cx| {
16485                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16486                })
16487            })?;
16488            let location = Some({
16489                let target_buffer_handle = location_task.await.context("open local buffer")?;
16490                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16491                    let target_start = target_buffer
16492                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16493                    let target_end = target_buffer
16494                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16495                    target_buffer.anchor_after(target_start)
16496                        ..target_buffer.anchor_before(target_end)
16497                })?;
16498                Location {
16499                    buffer: target_buffer_handle,
16500                    range,
16501                }
16502            });
16503            Ok(location)
16504        })
16505    }
16506
16507    pub fn find_all_references(
16508        &mut self,
16509        _: &FindAllReferences,
16510        window: &mut Window,
16511        cx: &mut Context<Self>,
16512    ) -> Option<Task<Result<Navigated>>> {
16513        let selection = self.selections.newest::<usize>(cx);
16514        let multi_buffer = self.buffer.read(cx);
16515        let head = selection.head();
16516
16517        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16518        let head_anchor = multi_buffer_snapshot.anchor_at(
16519            head,
16520            if head < selection.tail() {
16521                Bias::Right
16522            } else {
16523                Bias::Left
16524            },
16525        );
16526
16527        match self
16528            .find_all_references_task_sources
16529            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16530        {
16531            Ok(_) => {
16532                log::info!(
16533                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16534                );
16535                return None;
16536            }
16537            Err(i) => {
16538                self.find_all_references_task_sources.insert(i, head_anchor);
16539            }
16540        }
16541
16542        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16543        let workspace = self.workspace()?;
16544        let project = workspace.read(cx).project().clone();
16545        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16546        Some(cx.spawn_in(window, async move |editor, cx| {
16547            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16548                if let Ok(i) = editor
16549                    .find_all_references_task_sources
16550                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16551                {
16552                    editor.find_all_references_task_sources.remove(i);
16553                }
16554            });
16555
16556            let Some(locations) = references.await? else {
16557                return anyhow::Ok(Navigated::No);
16558            };
16559            if locations.is_empty() {
16560                return anyhow::Ok(Navigated::No);
16561            }
16562
16563            workspace.update_in(cx, |workspace, window, cx| {
16564                let target = locations
16565                    .iter()
16566                    .map(|location| {
16567                        location
16568                            .buffer
16569                            .read(cx)
16570                            .text_for_range(location.range.clone())
16571                            .collect::<String>()
16572                    })
16573                    .filter(|text| !text.contains('\n'))
16574                    .unique()
16575                    .take(3)
16576                    .join(", ");
16577                let title = if target.is_empty() {
16578                    "References".to_owned()
16579                } else {
16580                    format!("References to {target}")
16581                };
16582                Self::open_locations_in_multibuffer(
16583                    workspace,
16584                    locations,
16585                    title,
16586                    false,
16587                    MultibufferSelectionMode::First,
16588                    window,
16589                    cx,
16590                );
16591                Navigated::Yes
16592            })
16593        }))
16594    }
16595
16596    /// Opens a multibuffer with the given project locations in it
16597    pub fn open_locations_in_multibuffer(
16598        workspace: &mut Workspace,
16599        mut locations: Vec<Location>,
16600        title: String,
16601        split: bool,
16602        multibuffer_selection_mode: MultibufferSelectionMode,
16603        window: &mut Window,
16604        cx: &mut Context<Workspace>,
16605    ) {
16606        if locations.is_empty() {
16607            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16608            return;
16609        }
16610
16611        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16612
16613        let mut locations = locations.into_iter().peekable();
16614        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16615        let capability = workspace.project().read(cx).capability();
16616
16617        // a key to find existing multibuffer editors with the same set of locations
16618        // to prevent us from opening more and more multibuffer tabs for searches and the like
16619        let mut key = (title.clone(), vec![]);
16620        let excerpt_buffer = cx.new(|cx| {
16621            let key = &mut key.1;
16622            let mut multibuffer = MultiBuffer::new(capability);
16623            while let Some(location) = locations.next() {
16624                let buffer = location.buffer.read(cx);
16625                let mut ranges_for_buffer = Vec::new();
16626                let range = location.range.to_point(buffer);
16627                ranges_for_buffer.push(range.clone());
16628
16629                while let Some(next_location) =
16630                    locations.next_if(|next_location| next_location.buffer == location.buffer)
16631                {
16632                    ranges_for_buffer.push(next_location.range.to_point(buffer));
16633                }
16634
16635                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16636                key.push((
16637                    location.buffer.read(cx).remote_id(),
16638                    ranges_for_buffer.clone(),
16639                ));
16640                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16641                    PathKey::for_buffer(&location.buffer, cx),
16642                    location.buffer.clone(),
16643                    ranges_for_buffer,
16644                    multibuffer_context_lines(cx),
16645                    cx,
16646                );
16647                ranges.extend(new_ranges)
16648            }
16649
16650            multibuffer.with_title(title)
16651        });
16652        let existing = workspace.active_pane().update(cx, |pane, cx| {
16653            pane.items()
16654                .filter_map(|item| item.downcast::<Editor>())
16655                .find(|editor| {
16656                    editor
16657                        .read(cx)
16658                        .lookup_key
16659                        .as_ref()
16660                        .and_then(|it| {
16661                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16662                        })
16663                        .is_some_and(|it| *it == key)
16664                })
16665        });
16666        let editor = existing.unwrap_or_else(|| {
16667            cx.new(|cx| {
16668                let mut editor = Editor::for_multibuffer(
16669                    excerpt_buffer,
16670                    Some(workspace.project().clone()),
16671                    window,
16672                    cx,
16673                );
16674                editor.lookup_key = Some(Box::new(key));
16675                editor
16676            })
16677        });
16678        editor.update(cx, |editor, cx| {
16679            match multibuffer_selection_mode {
16680                MultibufferSelectionMode::First => {
16681                    if let Some(first_range) = ranges.first() {
16682                        editor.change_selections(
16683                            SelectionEffects::no_scroll(),
16684                            window,
16685                            cx,
16686                            |selections| {
16687                                selections.clear_disjoint();
16688                                selections
16689                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16690                            },
16691                        );
16692                    }
16693                    editor.highlight_background::<Self>(
16694                        &ranges,
16695                        |theme| theme.colors().editor_highlighted_line_background,
16696                        cx,
16697                    );
16698                }
16699                MultibufferSelectionMode::All => {
16700                    editor.change_selections(
16701                        SelectionEffects::no_scroll(),
16702                        window,
16703                        cx,
16704                        |selections| {
16705                            selections.clear_disjoint();
16706                            selections.select_anchor_ranges(ranges);
16707                        },
16708                    );
16709                }
16710            }
16711            editor.register_buffers_with_language_servers(cx);
16712        });
16713
16714        let item = Box::new(editor);
16715        let item_id = item.item_id();
16716
16717        if split {
16718            workspace.split_item(SplitDirection::Right, item, window, cx);
16719        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16720            let (preview_item_id, preview_item_idx) =
16721                workspace.active_pane().read_with(cx, |pane, _| {
16722                    (pane.preview_item_id(), pane.preview_item_idx())
16723                });
16724
16725            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16726
16727            if let Some(preview_item_id) = preview_item_id {
16728                workspace.active_pane().update(cx, |pane, cx| {
16729                    pane.remove_item(preview_item_id, false, false, window, cx);
16730                });
16731            }
16732        } else {
16733            workspace.add_item_to_active_pane(item, None, true, window, cx);
16734        }
16735        workspace.active_pane().update(cx, |pane, cx| {
16736            pane.set_preview_item_id(Some(item_id), cx);
16737        });
16738    }
16739
16740    pub fn rename(
16741        &mut self,
16742        _: &Rename,
16743        window: &mut Window,
16744        cx: &mut Context<Self>,
16745    ) -> Option<Task<Result<()>>> {
16746        use language::ToOffset as _;
16747
16748        let provider = self.semantics_provider.clone()?;
16749        let selection = self.selections.newest_anchor().clone();
16750        let (cursor_buffer, cursor_buffer_position) = self
16751            .buffer
16752            .read(cx)
16753            .text_anchor_for_position(selection.head(), cx)?;
16754        let (tail_buffer, cursor_buffer_position_end) = self
16755            .buffer
16756            .read(cx)
16757            .text_anchor_for_position(selection.tail(), cx)?;
16758        if tail_buffer != cursor_buffer {
16759            return None;
16760        }
16761
16762        let snapshot = cursor_buffer.read(cx).snapshot();
16763        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16764        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16765        let prepare_rename = provider
16766            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16767            .unwrap_or_else(|| Task::ready(Ok(None)));
16768        drop(snapshot);
16769
16770        Some(cx.spawn_in(window, async move |this, cx| {
16771            let rename_range = if let Some(range) = prepare_rename.await? {
16772                Some(range)
16773            } else {
16774                this.update(cx, |this, cx| {
16775                    let buffer = this.buffer.read(cx).snapshot(cx);
16776                    let mut buffer_highlights = this
16777                        .document_highlights_for_position(selection.head(), &buffer)
16778                        .filter(|highlight| {
16779                            highlight.start.excerpt_id == selection.head().excerpt_id
16780                                && highlight.end.excerpt_id == selection.head().excerpt_id
16781                        });
16782                    buffer_highlights
16783                        .next()
16784                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16785                })?
16786            };
16787            if let Some(rename_range) = rename_range {
16788                this.update_in(cx, |this, window, cx| {
16789                    let snapshot = cursor_buffer.read(cx).snapshot();
16790                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16791                    let cursor_offset_in_rename_range =
16792                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16793                    let cursor_offset_in_rename_range_end =
16794                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16795
16796                    this.take_rename(false, window, cx);
16797                    let buffer = this.buffer.read(cx).read(cx);
16798                    let cursor_offset = selection.head().to_offset(&buffer);
16799                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16800                    let rename_end = rename_start + rename_buffer_range.len();
16801                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16802                    let mut old_highlight_id = None;
16803                    let old_name: Arc<str> = buffer
16804                        .chunks(rename_start..rename_end, true)
16805                        .map(|chunk| {
16806                            if old_highlight_id.is_none() {
16807                                old_highlight_id = chunk.syntax_highlight_id;
16808                            }
16809                            chunk.text
16810                        })
16811                        .collect::<String>()
16812                        .into();
16813
16814                    drop(buffer);
16815
16816                    // Position the selection in the rename editor so that it matches the current selection.
16817                    this.show_local_selections = false;
16818                    let rename_editor = cx.new(|cx| {
16819                        let mut editor = Editor::single_line(window, cx);
16820                        editor.buffer.update(cx, |buffer, cx| {
16821                            buffer.edit([(0..0, old_name.clone())], None, cx)
16822                        });
16823                        let rename_selection_range = match cursor_offset_in_rename_range
16824                            .cmp(&cursor_offset_in_rename_range_end)
16825                        {
16826                            Ordering::Equal => {
16827                                editor.select_all(&SelectAll, window, cx);
16828                                return editor;
16829                            }
16830                            Ordering::Less => {
16831                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16832                            }
16833                            Ordering::Greater => {
16834                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16835                            }
16836                        };
16837                        if rename_selection_range.end > old_name.len() {
16838                            editor.select_all(&SelectAll, window, cx);
16839                        } else {
16840                            editor.change_selections(Default::default(), window, cx, |s| {
16841                                s.select_ranges([rename_selection_range]);
16842                            });
16843                        }
16844                        editor
16845                    });
16846                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16847                        if e == &EditorEvent::Focused {
16848                            cx.emit(EditorEvent::FocusedIn)
16849                        }
16850                    })
16851                    .detach();
16852
16853                    let write_highlights =
16854                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16855                    let read_highlights =
16856                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16857                    let ranges = write_highlights
16858                        .iter()
16859                        .flat_map(|(_, ranges)| ranges.iter())
16860                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16861                        .cloned()
16862                        .collect();
16863
16864                    this.highlight_text::<Rename>(
16865                        ranges,
16866                        HighlightStyle {
16867                            fade_out: Some(0.6),
16868                            ..Default::default()
16869                        },
16870                        cx,
16871                    );
16872                    let rename_focus_handle = rename_editor.focus_handle(cx);
16873                    window.focus(&rename_focus_handle);
16874                    let block_id = this.insert_blocks(
16875                        [BlockProperties {
16876                            style: BlockStyle::Flex,
16877                            placement: BlockPlacement::Below(range.start),
16878                            height: Some(1),
16879                            render: Arc::new({
16880                                let rename_editor = rename_editor.clone();
16881                                move |cx: &mut BlockContext| {
16882                                    let mut text_style = cx.editor_style.text.clone();
16883                                    if let Some(highlight_style) = old_highlight_id
16884                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16885                                    {
16886                                        text_style = text_style.highlight(highlight_style);
16887                                    }
16888                                    div()
16889                                        .block_mouse_except_scroll()
16890                                        .pl(cx.anchor_x)
16891                                        .child(EditorElement::new(
16892                                            &rename_editor,
16893                                            EditorStyle {
16894                                                background: cx.theme().system().transparent,
16895                                                local_player: cx.editor_style.local_player,
16896                                                text: text_style,
16897                                                scrollbar_width: cx.editor_style.scrollbar_width,
16898                                                syntax: cx.editor_style.syntax.clone(),
16899                                                status: cx.editor_style.status.clone(),
16900                                                inlay_hints_style: HighlightStyle {
16901                                                    font_weight: Some(FontWeight::BOLD),
16902                                                    ..make_inlay_hints_style(cx.app)
16903                                                },
16904                                                edit_prediction_styles: make_suggestion_styles(
16905                                                    cx.app,
16906                                                ),
16907                                                ..EditorStyle::default()
16908                                            },
16909                                        ))
16910                                        .into_any_element()
16911                                }
16912                            }),
16913                            priority: 0,
16914                        }],
16915                        Some(Autoscroll::fit()),
16916                        cx,
16917                    )[0];
16918                    this.pending_rename = Some(RenameState {
16919                        range,
16920                        old_name,
16921                        editor: rename_editor,
16922                        block_id,
16923                    });
16924                })?;
16925            }
16926
16927            Ok(())
16928        }))
16929    }
16930
16931    pub fn confirm_rename(
16932        &mut self,
16933        _: &ConfirmRename,
16934        window: &mut Window,
16935        cx: &mut Context<Self>,
16936    ) -> Option<Task<Result<()>>> {
16937        let rename = self.take_rename(false, window, cx)?;
16938        let workspace = self.workspace()?.downgrade();
16939        let (buffer, start) = self
16940            .buffer
16941            .read(cx)
16942            .text_anchor_for_position(rename.range.start, cx)?;
16943        let (end_buffer, _) = self
16944            .buffer
16945            .read(cx)
16946            .text_anchor_for_position(rename.range.end, cx)?;
16947        if buffer != end_buffer {
16948            return None;
16949        }
16950
16951        let old_name = rename.old_name;
16952        let new_name = rename.editor.read(cx).text(cx);
16953
16954        let rename = self.semantics_provider.as_ref()?.perform_rename(
16955            &buffer,
16956            start,
16957            new_name.clone(),
16958            cx,
16959        )?;
16960
16961        Some(cx.spawn_in(window, async move |editor, cx| {
16962            let project_transaction = rename.await?;
16963            Self::open_project_transaction(
16964                &editor,
16965                workspace,
16966                project_transaction,
16967                format!("Rename: {}{}", old_name, new_name),
16968                cx,
16969            )
16970            .await?;
16971
16972            editor.update(cx, |editor, cx| {
16973                editor.refresh_document_highlights(cx);
16974            })?;
16975            Ok(())
16976        }))
16977    }
16978
16979    fn take_rename(
16980        &mut self,
16981        moving_cursor: bool,
16982        window: &mut Window,
16983        cx: &mut Context<Self>,
16984    ) -> Option<RenameState> {
16985        let rename = self.pending_rename.take()?;
16986        if rename.editor.focus_handle(cx).is_focused(window) {
16987            window.focus(&self.focus_handle);
16988        }
16989
16990        self.remove_blocks(
16991            [rename.block_id].into_iter().collect(),
16992            Some(Autoscroll::fit()),
16993            cx,
16994        );
16995        self.clear_highlights::<Rename>(cx);
16996        self.show_local_selections = true;
16997
16998        if moving_cursor {
16999            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17000                editor.selections.newest::<usize>(cx).head()
17001            });
17002
17003            // Update the selection to match the position of the selection inside
17004            // the rename editor.
17005            let snapshot = self.buffer.read(cx).read(cx);
17006            let rename_range = rename.range.to_offset(&snapshot);
17007            let cursor_in_editor = snapshot
17008                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17009                .min(rename_range.end);
17010            drop(snapshot);
17011
17012            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17013                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17014            });
17015        } else {
17016            self.refresh_document_highlights(cx);
17017        }
17018
17019        Some(rename)
17020    }
17021
17022    pub fn pending_rename(&self) -> Option<&RenameState> {
17023        self.pending_rename.as_ref()
17024    }
17025
17026    fn format(
17027        &mut self,
17028        _: &Format,
17029        window: &mut Window,
17030        cx: &mut Context<Self>,
17031    ) -> Option<Task<Result<()>>> {
17032        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17033
17034        let project = match &self.project {
17035            Some(project) => project.clone(),
17036            None => return None,
17037        };
17038
17039        Some(self.perform_format(
17040            project,
17041            FormatTrigger::Manual,
17042            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17043            window,
17044            cx,
17045        ))
17046    }
17047
17048    fn format_selections(
17049        &mut self,
17050        _: &FormatSelections,
17051        window: &mut Window,
17052        cx: &mut Context<Self>,
17053    ) -> Option<Task<Result<()>>> {
17054        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17055
17056        let project = match &self.project {
17057            Some(project) => project.clone(),
17058            None => return None,
17059        };
17060
17061        let ranges = self
17062            .selections
17063            .all_adjusted(cx)
17064            .into_iter()
17065            .map(|selection| selection.range())
17066            .collect_vec();
17067
17068        Some(self.perform_format(
17069            project,
17070            FormatTrigger::Manual,
17071            FormatTarget::Ranges(ranges),
17072            window,
17073            cx,
17074        ))
17075    }
17076
17077    fn perform_format(
17078        &mut self,
17079        project: Entity<Project>,
17080        trigger: FormatTrigger,
17081        target: FormatTarget,
17082        window: &mut Window,
17083        cx: &mut Context<Self>,
17084    ) -> Task<Result<()>> {
17085        let buffer = self.buffer.clone();
17086        let (buffers, target) = match target {
17087            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17088            FormatTarget::Ranges(selection_ranges) => {
17089                let multi_buffer = buffer.read(cx);
17090                let snapshot = multi_buffer.read(cx);
17091                let mut buffers = HashSet::default();
17092                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17093                    BTreeMap::new();
17094                for selection_range in selection_ranges {
17095                    for (buffer, buffer_range, _) in
17096                        snapshot.range_to_buffer_ranges(selection_range)
17097                    {
17098                        let buffer_id = buffer.remote_id();
17099                        let start = buffer.anchor_before(buffer_range.start);
17100                        let end = buffer.anchor_after(buffer_range.end);
17101                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17102                        buffer_id_to_ranges
17103                            .entry(buffer_id)
17104                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17105                            .or_insert_with(|| vec![start..end]);
17106                    }
17107                }
17108                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17109            }
17110        };
17111
17112        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17113        let selections_prev = transaction_id_prev
17114            .and_then(|transaction_id_prev| {
17115                // default to selections as they were after the last edit, if we have them,
17116                // instead of how they are now.
17117                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17118                // will take you back to where you made the last edit, instead of staying where you scrolled
17119                self.selection_history
17120                    .transaction(transaction_id_prev)
17121                    .map(|t| t.0.clone())
17122            })
17123            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17124
17125        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17126        let format = project.update(cx, |project, cx| {
17127            project.format(buffers, target, true, trigger, cx)
17128        });
17129
17130        cx.spawn_in(window, async move |editor, cx| {
17131            let transaction = futures::select_biased! {
17132                transaction = format.log_err().fuse() => transaction,
17133                () = timeout => {
17134                    log::warn!("timed out waiting for formatting");
17135                    None
17136                }
17137            };
17138
17139            buffer
17140                .update(cx, |buffer, cx| {
17141                    if let Some(transaction) = transaction
17142                        && !buffer.is_singleton()
17143                    {
17144                        buffer.push_transaction(&transaction.0, cx);
17145                    }
17146                    cx.notify();
17147                })
17148                .ok();
17149
17150            if let Some(transaction_id_now) =
17151                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17152            {
17153                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17154                if has_new_transaction {
17155                    _ = editor.update(cx, |editor, _| {
17156                        editor
17157                            .selection_history
17158                            .insert_transaction(transaction_id_now, selections_prev);
17159                    });
17160                }
17161            }
17162
17163            Ok(())
17164        })
17165    }
17166
17167    fn organize_imports(
17168        &mut self,
17169        _: &OrganizeImports,
17170        window: &mut Window,
17171        cx: &mut Context<Self>,
17172    ) -> Option<Task<Result<()>>> {
17173        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17174        let project = match &self.project {
17175            Some(project) => project.clone(),
17176            None => return None,
17177        };
17178        Some(self.perform_code_action_kind(
17179            project,
17180            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17181            window,
17182            cx,
17183        ))
17184    }
17185
17186    fn perform_code_action_kind(
17187        &mut self,
17188        project: Entity<Project>,
17189        kind: CodeActionKind,
17190        window: &mut Window,
17191        cx: &mut Context<Self>,
17192    ) -> Task<Result<()>> {
17193        let buffer = self.buffer.clone();
17194        let buffers = buffer.read(cx).all_buffers();
17195        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17196        let apply_action = project.update(cx, |project, cx| {
17197            project.apply_code_action_kind(buffers, kind, true, cx)
17198        });
17199        cx.spawn_in(window, async move |_, cx| {
17200            let transaction = futures::select_biased! {
17201                () = timeout => {
17202                    log::warn!("timed out waiting for executing code action");
17203                    None
17204                }
17205                transaction = apply_action.log_err().fuse() => transaction,
17206            };
17207            buffer
17208                .update(cx, |buffer, cx| {
17209                    // check if we need this
17210                    if let Some(transaction) = transaction
17211                        && !buffer.is_singleton()
17212                    {
17213                        buffer.push_transaction(&transaction.0, cx);
17214                    }
17215                    cx.notify();
17216                })
17217                .ok();
17218            Ok(())
17219        })
17220    }
17221
17222    pub fn restart_language_server(
17223        &mut self,
17224        _: &RestartLanguageServer,
17225        _: &mut Window,
17226        cx: &mut Context<Self>,
17227    ) {
17228        if let Some(project) = self.project.clone() {
17229            self.buffer.update(cx, |multi_buffer, cx| {
17230                project.update(cx, |project, cx| {
17231                    project.restart_language_servers_for_buffers(
17232                        multi_buffer.all_buffers().into_iter().collect(),
17233                        HashSet::default(),
17234                        cx,
17235                    );
17236                });
17237            })
17238        }
17239    }
17240
17241    pub fn stop_language_server(
17242        &mut self,
17243        _: &StopLanguageServer,
17244        _: &mut Window,
17245        cx: &mut Context<Self>,
17246    ) {
17247        if let Some(project) = self.project.clone() {
17248            self.buffer.update(cx, |multi_buffer, cx| {
17249                project.update(cx, |project, cx| {
17250                    project.stop_language_servers_for_buffers(
17251                        multi_buffer.all_buffers().into_iter().collect(),
17252                        HashSet::default(),
17253                        cx,
17254                    );
17255                    cx.emit(project::Event::RefreshInlayHints);
17256                });
17257            });
17258        }
17259    }
17260
17261    fn cancel_language_server_work(
17262        workspace: &mut Workspace,
17263        _: &actions::CancelLanguageServerWork,
17264        _: &mut Window,
17265        cx: &mut Context<Workspace>,
17266    ) {
17267        let project = workspace.project();
17268        let buffers = workspace
17269            .active_item(cx)
17270            .and_then(|item| item.act_as::<Editor>(cx))
17271            .map_or(HashSet::default(), |editor| {
17272                editor.read(cx).buffer.read(cx).all_buffers()
17273            });
17274        project.update(cx, |project, cx| {
17275            project.cancel_language_server_work_for_buffers(buffers, cx);
17276        });
17277    }
17278
17279    fn show_character_palette(
17280        &mut self,
17281        _: &ShowCharacterPalette,
17282        window: &mut Window,
17283        _: &mut Context<Self>,
17284    ) {
17285        window.show_character_palette();
17286    }
17287
17288    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17289        if !self.diagnostics_enabled() {
17290            return;
17291        }
17292
17293        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17294            let buffer = self.buffer.read(cx).snapshot(cx);
17295            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17296            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17297            let is_valid = buffer
17298                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17299                .any(|entry| {
17300                    entry.diagnostic.is_primary
17301                        && !entry.range.is_empty()
17302                        && entry.range.start == primary_range_start
17303                        && entry.diagnostic.message == active_diagnostics.active_message
17304                });
17305
17306            if !is_valid {
17307                self.dismiss_diagnostics(cx);
17308            }
17309        }
17310    }
17311
17312    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17313        match &self.active_diagnostics {
17314            ActiveDiagnostic::Group(group) => Some(group),
17315            _ => None,
17316        }
17317    }
17318
17319    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17320        if !self.diagnostics_enabled() {
17321            return;
17322        }
17323        self.dismiss_diagnostics(cx);
17324        self.active_diagnostics = ActiveDiagnostic::All;
17325    }
17326
17327    fn activate_diagnostics(
17328        &mut self,
17329        buffer_id: BufferId,
17330        diagnostic: DiagnosticEntry<usize>,
17331        window: &mut Window,
17332        cx: &mut Context<Self>,
17333    ) {
17334        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17335            return;
17336        }
17337        self.dismiss_diagnostics(cx);
17338        let snapshot = self.snapshot(window, cx);
17339        let buffer = self.buffer.read(cx).snapshot(cx);
17340        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17341            return;
17342        };
17343
17344        let diagnostic_group = buffer
17345            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17346            .collect::<Vec<_>>();
17347
17348        let blocks =
17349            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17350
17351        let blocks = self.display_map.update(cx, |display_map, cx| {
17352            display_map.insert_blocks(blocks, cx).into_iter().collect()
17353        });
17354        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17355            active_range: buffer.anchor_before(diagnostic.range.start)
17356                ..buffer.anchor_after(diagnostic.range.end),
17357            active_message: diagnostic.diagnostic.message.clone(),
17358            group_id: diagnostic.diagnostic.group_id,
17359            blocks,
17360        });
17361        cx.notify();
17362    }
17363
17364    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17365        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17366            return;
17367        };
17368
17369        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17370        if let ActiveDiagnostic::Group(group) = prev {
17371            self.display_map.update(cx, |display_map, cx| {
17372                display_map.remove_blocks(group.blocks, cx);
17373            });
17374            cx.notify();
17375        }
17376    }
17377
17378    /// Disable inline diagnostics rendering for this editor.
17379    pub fn disable_inline_diagnostics(&mut self) {
17380        self.inline_diagnostics_enabled = false;
17381        self.inline_diagnostics_update = Task::ready(());
17382        self.inline_diagnostics.clear();
17383    }
17384
17385    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17386        self.diagnostics_enabled = false;
17387        self.dismiss_diagnostics(cx);
17388        self.inline_diagnostics_update = Task::ready(());
17389        self.inline_diagnostics.clear();
17390    }
17391
17392    pub fn disable_word_completions(&mut self) {
17393        self.word_completions_enabled = false;
17394    }
17395
17396    pub fn diagnostics_enabled(&self) -> bool {
17397        self.diagnostics_enabled && self.mode.is_full()
17398    }
17399
17400    pub fn inline_diagnostics_enabled(&self) -> bool {
17401        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17402    }
17403
17404    pub fn show_inline_diagnostics(&self) -> bool {
17405        self.show_inline_diagnostics
17406    }
17407
17408    pub fn toggle_inline_diagnostics(
17409        &mut self,
17410        _: &ToggleInlineDiagnostics,
17411        window: &mut Window,
17412        cx: &mut Context<Editor>,
17413    ) {
17414        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17415        self.refresh_inline_diagnostics(false, window, cx);
17416    }
17417
17418    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17419        self.diagnostics_max_severity = severity;
17420        self.display_map.update(cx, |display_map, _| {
17421            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17422        });
17423    }
17424
17425    pub fn toggle_diagnostics(
17426        &mut self,
17427        _: &ToggleDiagnostics,
17428        window: &mut Window,
17429        cx: &mut Context<Editor>,
17430    ) {
17431        if !self.diagnostics_enabled() {
17432            return;
17433        }
17434
17435        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17436            EditorSettings::get_global(cx)
17437                .diagnostics_max_severity
17438                .filter(|severity| severity != &DiagnosticSeverity::Off)
17439                .unwrap_or(DiagnosticSeverity::Hint)
17440        } else {
17441            DiagnosticSeverity::Off
17442        };
17443        self.set_max_diagnostics_severity(new_severity, cx);
17444        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17445            self.active_diagnostics = ActiveDiagnostic::None;
17446            self.inline_diagnostics_update = Task::ready(());
17447            self.inline_diagnostics.clear();
17448        } else {
17449            self.refresh_inline_diagnostics(false, window, cx);
17450        }
17451
17452        cx.notify();
17453    }
17454
17455    pub fn toggle_minimap(
17456        &mut self,
17457        _: &ToggleMinimap,
17458        window: &mut Window,
17459        cx: &mut Context<Editor>,
17460    ) {
17461        if self.supports_minimap(cx) {
17462            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17463        }
17464    }
17465
17466    fn refresh_inline_diagnostics(
17467        &mut self,
17468        debounce: bool,
17469        window: &mut Window,
17470        cx: &mut Context<Self>,
17471    ) {
17472        let max_severity = ProjectSettings::get_global(cx)
17473            .diagnostics
17474            .inline
17475            .max_severity
17476            .unwrap_or(self.diagnostics_max_severity);
17477
17478        if !self.inline_diagnostics_enabled()
17479            || !self.show_inline_diagnostics
17480            || max_severity == DiagnosticSeverity::Off
17481        {
17482            self.inline_diagnostics_update = Task::ready(());
17483            self.inline_diagnostics.clear();
17484            return;
17485        }
17486
17487        let debounce_ms = ProjectSettings::get_global(cx)
17488            .diagnostics
17489            .inline
17490            .update_debounce_ms;
17491        let debounce = if debounce && debounce_ms > 0 {
17492            Some(Duration::from_millis(debounce_ms))
17493        } else {
17494            None
17495        };
17496        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17497            if let Some(debounce) = debounce {
17498                cx.background_executor().timer(debounce).await;
17499            }
17500            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17501                editor
17502                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17503                    .ok()
17504            }) else {
17505                return;
17506            };
17507
17508            let new_inline_diagnostics = cx
17509                .background_spawn(async move {
17510                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17511                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17512                        let message = diagnostic_entry
17513                            .diagnostic
17514                            .message
17515                            .split_once('\n')
17516                            .map(|(line, _)| line)
17517                            .map(SharedString::new)
17518                            .unwrap_or_else(|| {
17519                                SharedString::from(diagnostic_entry.diagnostic.message)
17520                            });
17521                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17522                        let (Ok(i) | Err(i)) = inline_diagnostics
17523                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17524                        inline_diagnostics.insert(
17525                            i,
17526                            (
17527                                start_anchor,
17528                                InlineDiagnostic {
17529                                    message,
17530                                    group_id: diagnostic_entry.diagnostic.group_id,
17531                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17532                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17533                                    severity: diagnostic_entry.diagnostic.severity,
17534                                },
17535                            ),
17536                        );
17537                    }
17538                    inline_diagnostics
17539                })
17540                .await;
17541
17542            editor
17543                .update(cx, |editor, cx| {
17544                    editor.inline_diagnostics = new_inline_diagnostics;
17545                    cx.notify();
17546                })
17547                .ok();
17548        });
17549    }
17550
17551    fn pull_diagnostics(
17552        &mut self,
17553        buffer_id: Option<BufferId>,
17554        window: &Window,
17555        cx: &mut Context<Self>,
17556    ) -> Option<()> {
17557        if !self.mode().is_full() {
17558            return None;
17559        }
17560        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17561            .diagnostics
17562            .lsp_pull_diagnostics;
17563        if !pull_diagnostics_settings.enabled {
17564            return None;
17565        }
17566        let project = self.project()?.downgrade();
17567        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17568        let mut buffers = self.buffer.read(cx).all_buffers();
17569        if let Some(buffer_id) = buffer_id {
17570            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17571        }
17572
17573        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17574            cx.background_executor().timer(debounce).await;
17575
17576            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17577                buffers
17578                    .into_iter()
17579                    .filter_map(|buffer| {
17580                        project
17581                            .update(cx, |project, cx| {
17582                                project.lsp_store().update(cx, |lsp_store, cx| {
17583                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17584                                })
17585                            })
17586                            .ok()
17587                    })
17588                    .collect::<FuturesUnordered<_>>()
17589            }) else {
17590                return;
17591            };
17592
17593            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17594                match pull_task {
17595                    Ok(()) => {
17596                        if editor
17597                            .update_in(cx, |editor, window, cx| {
17598                                editor.update_diagnostics_state(window, cx);
17599                            })
17600                            .is_err()
17601                        {
17602                            return;
17603                        }
17604                    }
17605                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17606                }
17607            }
17608        });
17609
17610        Some(())
17611    }
17612
17613    pub fn set_selections_from_remote(
17614        &mut self,
17615        selections: Vec<Selection<Anchor>>,
17616        pending_selection: Option<Selection<Anchor>>,
17617        window: &mut Window,
17618        cx: &mut Context<Self>,
17619    ) {
17620        let old_cursor_position = self.selections.newest_anchor().head();
17621        self.selections.change_with(cx, |s| {
17622            s.select_anchors(selections);
17623            if let Some(pending_selection) = pending_selection {
17624                s.set_pending(pending_selection, SelectMode::Character);
17625            } else {
17626                s.clear_pending();
17627            }
17628        });
17629        self.selections_did_change(
17630            false,
17631            &old_cursor_position,
17632            SelectionEffects::default(),
17633            window,
17634            cx,
17635        );
17636    }
17637
17638    pub fn transact(
17639        &mut self,
17640        window: &mut Window,
17641        cx: &mut Context<Self>,
17642        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17643    ) -> Option<TransactionId> {
17644        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17645            this.start_transaction_at(Instant::now(), window, cx);
17646            update(this, window, cx);
17647            this.end_transaction_at(Instant::now(), cx)
17648        })
17649    }
17650
17651    pub fn start_transaction_at(
17652        &mut self,
17653        now: Instant,
17654        window: &mut Window,
17655        cx: &mut Context<Self>,
17656    ) -> Option<TransactionId> {
17657        self.end_selection(window, cx);
17658        if let Some(tx_id) = self
17659            .buffer
17660            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17661        {
17662            self.selection_history
17663                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17664            cx.emit(EditorEvent::TransactionBegun {
17665                transaction_id: tx_id,
17666            });
17667            Some(tx_id)
17668        } else {
17669            None
17670        }
17671    }
17672
17673    pub fn end_transaction_at(
17674        &mut self,
17675        now: Instant,
17676        cx: &mut Context<Self>,
17677    ) -> Option<TransactionId> {
17678        if let Some(transaction_id) = self
17679            .buffer
17680            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17681        {
17682            if let Some((_, end_selections)) =
17683                self.selection_history.transaction_mut(transaction_id)
17684            {
17685                *end_selections = Some(self.selections.disjoint_anchors_arc());
17686            } else {
17687                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17688            }
17689
17690            cx.emit(EditorEvent::Edited { transaction_id });
17691            Some(transaction_id)
17692        } else {
17693            None
17694        }
17695    }
17696
17697    pub fn modify_transaction_selection_history(
17698        &mut self,
17699        transaction_id: TransactionId,
17700        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17701    ) -> bool {
17702        self.selection_history
17703            .transaction_mut(transaction_id)
17704            .map(modify)
17705            .is_some()
17706    }
17707
17708    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17709        if self.selection_mark_mode {
17710            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17711                s.move_with(|_, sel| {
17712                    sel.collapse_to(sel.head(), SelectionGoal::None);
17713                });
17714            })
17715        }
17716        self.selection_mark_mode = true;
17717        cx.notify();
17718    }
17719
17720    pub fn swap_selection_ends(
17721        &mut self,
17722        _: &actions::SwapSelectionEnds,
17723        window: &mut Window,
17724        cx: &mut Context<Self>,
17725    ) {
17726        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17727            s.move_with(|_, sel| {
17728                if sel.start != sel.end {
17729                    sel.reversed = !sel.reversed
17730                }
17731            });
17732        });
17733        self.request_autoscroll(Autoscroll::newest(), cx);
17734        cx.notify();
17735    }
17736
17737    pub fn toggle_focus(
17738        workspace: &mut Workspace,
17739        _: &actions::ToggleFocus,
17740        window: &mut Window,
17741        cx: &mut Context<Workspace>,
17742    ) {
17743        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17744            return;
17745        };
17746        workspace.activate_item(&item, true, true, window, cx);
17747    }
17748
17749    pub fn toggle_fold(
17750        &mut self,
17751        _: &actions::ToggleFold,
17752        window: &mut Window,
17753        cx: &mut Context<Self>,
17754    ) {
17755        if self.is_singleton(cx) {
17756            let selection = self.selections.newest::<Point>(cx);
17757
17758            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17759            let range = if selection.is_empty() {
17760                let point = selection.head().to_display_point(&display_map);
17761                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17762                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17763                    .to_point(&display_map);
17764                start..end
17765            } else {
17766                selection.range()
17767            };
17768            if display_map.folds_in_range(range).next().is_some() {
17769                self.unfold_lines(&Default::default(), window, cx)
17770            } else {
17771                self.fold(&Default::default(), window, cx)
17772            }
17773        } else {
17774            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17775            let buffer_ids: HashSet<_> = self
17776                .selections
17777                .disjoint_anchor_ranges()
17778                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17779                .collect();
17780
17781            let should_unfold = buffer_ids
17782                .iter()
17783                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17784
17785            for buffer_id in buffer_ids {
17786                if should_unfold {
17787                    self.unfold_buffer(buffer_id, cx);
17788                } else {
17789                    self.fold_buffer(buffer_id, cx);
17790                }
17791            }
17792        }
17793    }
17794
17795    pub fn toggle_fold_recursive(
17796        &mut self,
17797        _: &actions::ToggleFoldRecursive,
17798        window: &mut Window,
17799        cx: &mut Context<Self>,
17800    ) {
17801        let selection = self.selections.newest::<Point>(cx);
17802
17803        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17804        let range = if selection.is_empty() {
17805            let point = selection.head().to_display_point(&display_map);
17806            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17807            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17808                .to_point(&display_map);
17809            start..end
17810        } else {
17811            selection.range()
17812        };
17813        if display_map.folds_in_range(range).next().is_some() {
17814            self.unfold_recursive(&Default::default(), window, cx)
17815        } else {
17816            self.fold_recursive(&Default::default(), window, cx)
17817        }
17818    }
17819
17820    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17821        if self.is_singleton(cx) {
17822            let mut to_fold = Vec::new();
17823            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17824            let selections = self.selections.all_adjusted(cx);
17825
17826            for selection in selections {
17827                let range = selection.range().sorted();
17828                let buffer_start_row = range.start.row;
17829
17830                if range.start.row != range.end.row {
17831                    let mut found = false;
17832                    let mut row = range.start.row;
17833                    while row <= range.end.row {
17834                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17835                        {
17836                            found = true;
17837                            row = crease.range().end.row + 1;
17838                            to_fold.push(crease);
17839                        } else {
17840                            row += 1
17841                        }
17842                    }
17843                    if found {
17844                        continue;
17845                    }
17846                }
17847
17848                for row in (0..=range.start.row).rev() {
17849                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17850                        && crease.range().end.row >= buffer_start_row
17851                    {
17852                        to_fold.push(crease);
17853                        if row <= range.start.row {
17854                            break;
17855                        }
17856                    }
17857                }
17858            }
17859
17860            self.fold_creases(to_fold, true, window, cx);
17861        } else {
17862            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17863            let buffer_ids = self
17864                .selections
17865                .disjoint_anchor_ranges()
17866                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17867                .collect::<HashSet<_>>();
17868            for buffer_id in buffer_ids {
17869                self.fold_buffer(buffer_id, cx);
17870            }
17871        }
17872    }
17873
17874    pub fn toggle_fold_all(
17875        &mut self,
17876        _: &actions::ToggleFoldAll,
17877        window: &mut Window,
17878        cx: &mut Context<Self>,
17879    ) {
17880        if self.buffer.read(cx).is_singleton() {
17881            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17882            let has_folds = display_map
17883                .folds_in_range(0..display_map.buffer_snapshot.len())
17884                .next()
17885                .is_some();
17886
17887            if has_folds {
17888                self.unfold_all(&actions::UnfoldAll, window, cx);
17889            } else {
17890                self.fold_all(&actions::FoldAll, window, cx);
17891            }
17892        } else {
17893            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17894            let should_unfold = buffer_ids
17895                .iter()
17896                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17897
17898            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17899                editor
17900                    .update_in(cx, |editor, _, cx| {
17901                        for buffer_id in buffer_ids {
17902                            if should_unfold {
17903                                editor.unfold_buffer(buffer_id, cx);
17904                            } else {
17905                                editor.fold_buffer(buffer_id, cx);
17906                            }
17907                        }
17908                    })
17909                    .ok();
17910            });
17911        }
17912    }
17913
17914    fn fold_at_level(
17915        &mut self,
17916        fold_at: &FoldAtLevel,
17917        window: &mut Window,
17918        cx: &mut Context<Self>,
17919    ) {
17920        if !self.buffer.read(cx).is_singleton() {
17921            return;
17922        }
17923
17924        let fold_at_level = fold_at.0;
17925        let snapshot = self.buffer.read(cx).snapshot(cx);
17926        let mut to_fold = Vec::new();
17927        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17928
17929        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17930            while start_row < end_row {
17931                match self
17932                    .snapshot(window, cx)
17933                    .crease_for_buffer_row(MultiBufferRow(start_row))
17934                {
17935                    Some(crease) => {
17936                        let nested_start_row = crease.range().start.row + 1;
17937                        let nested_end_row = crease.range().end.row;
17938
17939                        if current_level < fold_at_level {
17940                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17941                        } else if current_level == fold_at_level {
17942                            to_fold.push(crease);
17943                        }
17944
17945                        start_row = nested_end_row + 1;
17946                    }
17947                    None => start_row += 1,
17948                }
17949            }
17950        }
17951
17952        self.fold_creases(to_fold, true, window, cx);
17953    }
17954
17955    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17956        if self.buffer.read(cx).is_singleton() {
17957            let mut fold_ranges = Vec::new();
17958            let snapshot = self.buffer.read(cx).snapshot(cx);
17959
17960            for row in 0..snapshot.max_row().0 {
17961                if let Some(foldable_range) = self
17962                    .snapshot(window, cx)
17963                    .crease_for_buffer_row(MultiBufferRow(row))
17964                {
17965                    fold_ranges.push(foldable_range);
17966                }
17967            }
17968
17969            self.fold_creases(fold_ranges, true, window, cx);
17970        } else {
17971            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17972                editor
17973                    .update_in(cx, |editor, _, cx| {
17974                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17975                            editor.fold_buffer(buffer_id, cx);
17976                        }
17977                    })
17978                    .ok();
17979            });
17980        }
17981    }
17982
17983    pub fn fold_function_bodies(
17984        &mut self,
17985        _: &actions::FoldFunctionBodies,
17986        window: &mut Window,
17987        cx: &mut Context<Self>,
17988    ) {
17989        let snapshot = self.buffer.read(cx).snapshot(cx);
17990
17991        let ranges = snapshot
17992            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17993            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17994            .collect::<Vec<_>>();
17995
17996        let creases = ranges
17997            .into_iter()
17998            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17999            .collect();
18000
18001        self.fold_creases(creases, true, window, cx);
18002    }
18003
18004    pub fn fold_recursive(
18005        &mut self,
18006        _: &actions::FoldRecursive,
18007        window: &mut Window,
18008        cx: &mut Context<Self>,
18009    ) {
18010        let mut to_fold = Vec::new();
18011        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18012        let selections = self.selections.all_adjusted(cx);
18013
18014        for selection in selections {
18015            let range = selection.range().sorted();
18016            let buffer_start_row = range.start.row;
18017
18018            if range.start.row != range.end.row {
18019                let mut found = false;
18020                for row in range.start.row..=range.end.row {
18021                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18022                        found = true;
18023                        to_fold.push(crease);
18024                    }
18025                }
18026                if found {
18027                    continue;
18028                }
18029            }
18030
18031            for row in (0..=range.start.row).rev() {
18032                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18033                    if crease.range().end.row >= buffer_start_row {
18034                        to_fold.push(crease);
18035                    } else {
18036                        break;
18037                    }
18038                }
18039            }
18040        }
18041
18042        self.fold_creases(to_fold, true, window, cx);
18043    }
18044
18045    pub fn fold_at(
18046        &mut self,
18047        buffer_row: MultiBufferRow,
18048        window: &mut Window,
18049        cx: &mut Context<Self>,
18050    ) {
18051        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18052
18053        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18054            let autoscroll = self
18055                .selections
18056                .all::<Point>(cx)
18057                .iter()
18058                .any(|selection| crease.range().overlaps(&selection.range()));
18059
18060            self.fold_creases(vec![crease], autoscroll, window, cx);
18061        }
18062    }
18063
18064    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18065        if self.is_singleton(cx) {
18066            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18067            let buffer = &display_map.buffer_snapshot;
18068            let selections = self.selections.all::<Point>(cx);
18069            let ranges = selections
18070                .iter()
18071                .map(|s| {
18072                    let range = s.display_range(&display_map).sorted();
18073                    let mut start = range.start.to_point(&display_map);
18074                    let mut end = range.end.to_point(&display_map);
18075                    start.column = 0;
18076                    end.column = buffer.line_len(MultiBufferRow(end.row));
18077                    start..end
18078                })
18079                .collect::<Vec<_>>();
18080
18081            self.unfold_ranges(&ranges, true, true, cx);
18082        } else {
18083            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18084            let buffer_ids = self
18085                .selections
18086                .disjoint_anchor_ranges()
18087                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18088                .collect::<HashSet<_>>();
18089            for buffer_id in buffer_ids {
18090                self.unfold_buffer(buffer_id, cx);
18091            }
18092        }
18093    }
18094
18095    pub fn unfold_recursive(
18096        &mut self,
18097        _: &UnfoldRecursive,
18098        _window: &mut Window,
18099        cx: &mut Context<Self>,
18100    ) {
18101        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18102        let selections = self.selections.all::<Point>(cx);
18103        let ranges = selections
18104            .iter()
18105            .map(|s| {
18106                let mut range = s.display_range(&display_map).sorted();
18107                *range.start.column_mut() = 0;
18108                *range.end.column_mut() = display_map.line_len(range.end.row());
18109                let start = range.start.to_point(&display_map);
18110                let end = range.end.to_point(&display_map);
18111                start..end
18112            })
18113            .collect::<Vec<_>>();
18114
18115        self.unfold_ranges(&ranges, true, true, cx);
18116    }
18117
18118    pub fn unfold_at(
18119        &mut self,
18120        buffer_row: MultiBufferRow,
18121        _window: &mut Window,
18122        cx: &mut Context<Self>,
18123    ) {
18124        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18125
18126        let intersection_range = Point::new(buffer_row.0, 0)
18127            ..Point::new(
18128                buffer_row.0,
18129                display_map.buffer_snapshot.line_len(buffer_row),
18130            );
18131
18132        let autoscroll = self
18133            .selections
18134            .all::<Point>(cx)
18135            .iter()
18136            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18137
18138        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18139    }
18140
18141    pub fn unfold_all(
18142        &mut self,
18143        _: &actions::UnfoldAll,
18144        _window: &mut Window,
18145        cx: &mut Context<Self>,
18146    ) {
18147        if self.buffer.read(cx).is_singleton() {
18148            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18149            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18150        } else {
18151            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18152                editor
18153                    .update(cx, |editor, cx| {
18154                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18155                            editor.unfold_buffer(buffer_id, cx);
18156                        }
18157                    })
18158                    .ok();
18159            });
18160        }
18161    }
18162
18163    pub fn fold_selected_ranges(
18164        &mut self,
18165        _: &FoldSelectedRanges,
18166        window: &mut Window,
18167        cx: &mut Context<Self>,
18168    ) {
18169        let selections = self.selections.all_adjusted(cx);
18170        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18171        let ranges = selections
18172            .into_iter()
18173            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18174            .collect::<Vec<_>>();
18175        self.fold_creases(ranges, true, window, cx);
18176    }
18177
18178    pub fn fold_ranges<T: ToOffset + Clone>(
18179        &mut self,
18180        ranges: Vec<Range<T>>,
18181        auto_scroll: bool,
18182        window: &mut Window,
18183        cx: &mut Context<Self>,
18184    ) {
18185        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18186        let ranges = ranges
18187            .into_iter()
18188            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18189            .collect::<Vec<_>>();
18190        self.fold_creases(ranges, auto_scroll, window, cx);
18191    }
18192
18193    pub fn fold_creases<T: ToOffset + Clone>(
18194        &mut self,
18195        creases: Vec<Crease<T>>,
18196        auto_scroll: bool,
18197        _window: &mut Window,
18198        cx: &mut Context<Self>,
18199    ) {
18200        if creases.is_empty() {
18201            return;
18202        }
18203
18204        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18205
18206        if auto_scroll {
18207            self.request_autoscroll(Autoscroll::fit(), cx);
18208        }
18209
18210        cx.notify();
18211
18212        self.scrollbar_marker_state.dirty = true;
18213        self.folds_did_change(cx);
18214    }
18215
18216    /// Removes any folds whose ranges intersect any of the given ranges.
18217    pub fn unfold_ranges<T: ToOffset + Clone>(
18218        &mut self,
18219        ranges: &[Range<T>],
18220        inclusive: bool,
18221        auto_scroll: bool,
18222        cx: &mut Context<Self>,
18223    ) {
18224        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18225            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18226        });
18227        self.folds_did_change(cx);
18228    }
18229
18230    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18231        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18232            return;
18233        }
18234        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18235        self.display_map.update(cx, |display_map, cx| {
18236            display_map.fold_buffers([buffer_id], cx)
18237        });
18238        cx.emit(EditorEvent::BufferFoldToggled {
18239            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18240            folded: true,
18241        });
18242        cx.notify();
18243    }
18244
18245    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18246        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18247            return;
18248        }
18249        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18250        self.display_map.update(cx, |display_map, cx| {
18251            display_map.unfold_buffers([buffer_id], cx);
18252        });
18253        cx.emit(EditorEvent::BufferFoldToggled {
18254            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18255            folded: false,
18256        });
18257        cx.notify();
18258    }
18259
18260    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18261        self.display_map.read(cx).is_buffer_folded(buffer)
18262    }
18263
18264    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18265        self.display_map.read(cx).folded_buffers()
18266    }
18267
18268    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18269        self.display_map.update(cx, |display_map, cx| {
18270            display_map.disable_header_for_buffer(buffer_id, cx);
18271        });
18272        cx.notify();
18273    }
18274
18275    /// Removes any folds with the given ranges.
18276    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18277        &mut self,
18278        ranges: &[Range<T>],
18279        type_id: TypeId,
18280        auto_scroll: bool,
18281        cx: &mut Context<Self>,
18282    ) {
18283        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18284            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18285        });
18286        self.folds_did_change(cx);
18287    }
18288
18289    fn remove_folds_with<T: ToOffset + Clone>(
18290        &mut self,
18291        ranges: &[Range<T>],
18292        auto_scroll: bool,
18293        cx: &mut Context<Self>,
18294        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18295    ) {
18296        if ranges.is_empty() {
18297            return;
18298        }
18299
18300        let mut buffers_affected = HashSet::default();
18301        let multi_buffer = self.buffer().read(cx);
18302        for range in ranges {
18303            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18304                buffers_affected.insert(buffer.read(cx).remote_id());
18305            };
18306        }
18307
18308        self.display_map.update(cx, update);
18309
18310        if auto_scroll {
18311            self.request_autoscroll(Autoscroll::fit(), cx);
18312        }
18313
18314        cx.notify();
18315        self.scrollbar_marker_state.dirty = true;
18316        self.active_indent_guides_state.dirty = true;
18317    }
18318
18319    pub fn update_renderer_widths(
18320        &mut self,
18321        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18322        cx: &mut Context<Self>,
18323    ) -> bool {
18324        self.display_map
18325            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18326    }
18327
18328    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18329        self.display_map.read(cx).fold_placeholder.clone()
18330    }
18331
18332    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18333        self.buffer.update(cx, |buffer, cx| {
18334            buffer.set_all_diff_hunks_expanded(cx);
18335        });
18336    }
18337
18338    pub fn expand_all_diff_hunks(
18339        &mut self,
18340        _: &ExpandAllDiffHunks,
18341        _window: &mut Window,
18342        cx: &mut Context<Self>,
18343    ) {
18344        self.buffer.update(cx, |buffer, cx| {
18345            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18346        });
18347    }
18348
18349    pub fn toggle_selected_diff_hunks(
18350        &mut self,
18351        _: &ToggleSelectedDiffHunks,
18352        _window: &mut Window,
18353        cx: &mut Context<Self>,
18354    ) {
18355        let ranges: Vec<_> = self
18356            .selections
18357            .disjoint_anchors()
18358            .iter()
18359            .map(|s| s.range())
18360            .collect();
18361        self.toggle_diff_hunks_in_ranges(ranges, cx);
18362    }
18363
18364    pub fn diff_hunks_in_ranges<'a>(
18365        &'a self,
18366        ranges: &'a [Range<Anchor>],
18367        buffer: &'a MultiBufferSnapshot,
18368    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18369        ranges.iter().flat_map(move |range| {
18370            let end_excerpt_id = range.end.excerpt_id;
18371            let range = range.to_point(buffer);
18372            let mut peek_end = range.end;
18373            if range.end.row < buffer.max_row().0 {
18374                peek_end = Point::new(range.end.row + 1, 0);
18375            }
18376            buffer
18377                .diff_hunks_in_range(range.start..peek_end)
18378                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18379        })
18380    }
18381
18382    pub fn has_stageable_diff_hunks_in_ranges(
18383        &self,
18384        ranges: &[Range<Anchor>],
18385        snapshot: &MultiBufferSnapshot,
18386    ) -> bool {
18387        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18388        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18389    }
18390
18391    pub fn toggle_staged_selected_diff_hunks(
18392        &mut self,
18393        _: &::git::ToggleStaged,
18394        _: &mut Window,
18395        cx: &mut Context<Self>,
18396    ) {
18397        let snapshot = self.buffer.read(cx).snapshot(cx);
18398        let ranges: Vec<_> = self
18399            .selections
18400            .disjoint_anchors()
18401            .iter()
18402            .map(|s| s.range())
18403            .collect();
18404        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18405        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18406    }
18407
18408    pub fn set_render_diff_hunk_controls(
18409        &mut self,
18410        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18411        cx: &mut Context<Self>,
18412    ) {
18413        self.render_diff_hunk_controls = render_diff_hunk_controls;
18414        cx.notify();
18415    }
18416
18417    pub fn stage_and_next(
18418        &mut self,
18419        _: &::git::StageAndNext,
18420        window: &mut Window,
18421        cx: &mut Context<Self>,
18422    ) {
18423        self.do_stage_or_unstage_and_next(true, window, cx);
18424    }
18425
18426    pub fn unstage_and_next(
18427        &mut self,
18428        _: &::git::UnstageAndNext,
18429        window: &mut Window,
18430        cx: &mut Context<Self>,
18431    ) {
18432        self.do_stage_or_unstage_and_next(false, window, cx);
18433    }
18434
18435    pub fn stage_or_unstage_diff_hunks(
18436        &mut self,
18437        stage: bool,
18438        ranges: Vec<Range<Anchor>>,
18439        cx: &mut Context<Self>,
18440    ) {
18441        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18442        cx.spawn(async move |this, cx| {
18443            task.await?;
18444            this.update(cx, |this, cx| {
18445                let snapshot = this.buffer.read(cx).snapshot(cx);
18446                let chunk_by = this
18447                    .diff_hunks_in_ranges(&ranges, &snapshot)
18448                    .chunk_by(|hunk| hunk.buffer_id);
18449                for (buffer_id, hunks) in &chunk_by {
18450                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18451                }
18452            })
18453        })
18454        .detach_and_log_err(cx);
18455    }
18456
18457    fn save_buffers_for_ranges_if_needed(
18458        &mut self,
18459        ranges: &[Range<Anchor>],
18460        cx: &mut Context<Editor>,
18461    ) -> Task<Result<()>> {
18462        let multibuffer = self.buffer.read(cx);
18463        let snapshot = multibuffer.read(cx);
18464        let buffer_ids: HashSet<_> = ranges
18465            .iter()
18466            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18467            .collect();
18468        drop(snapshot);
18469
18470        let mut buffers = HashSet::default();
18471        for buffer_id in buffer_ids {
18472            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18473                let buffer = buffer_entity.read(cx);
18474                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18475                {
18476                    buffers.insert(buffer_entity);
18477                }
18478            }
18479        }
18480
18481        if let Some(project) = &self.project {
18482            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18483        } else {
18484            Task::ready(Ok(()))
18485        }
18486    }
18487
18488    fn do_stage_or_unstage_and_next(
18489        &mut self,
18490        stage: bool,
18491        window: &mut Window,
18492        cx: &mut Context<Self>,
18493    ) {
18494        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18495
18496        if ranges.iter().any(|range| range.start != range.end) {
18497            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18498            return;
18499        }
18500
18501        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18502        let snapshot = self.snapshot(window, cx);
18503        let position = self.selections.newest::<Point>(cx).head();
18504        let mut row = snapshot
18505            .buffer_snapshot
18506            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18507            .find(|hunk| hunk.row_range.start.0 > position.row)
18508            .map(|hunk| hunk.row_range.start);
18509
18510        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18511        // Outside of the project diff editor, wrap around to the beginning.
18512        if !all_diff_hunks_expanded {
18513            row = row.or_else(|| {
18514                snapshot
18515                    .buffer_snapshot
18516                    .diff_hunks_in_range(Point::zero()..position)
18517                    .find(|hunk| hunk.row_range.end.0 < position.row)
18518                    .map(|hunk| hunk.row_range.start)
18519            });
18520        }
18521
18522        if let Some(row) = row {
18523            let destination = Point::new(row.0, 0);
18524            let autoscroll = Autoscroll::center();
18525
18526            self.unfold_ranges(&[destination..destination], false, false, cx);
18527            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18528                s.select_ranges([destination..destination]);
18529            });
18530        }
18531    }
18532
18533    fn do_stage_or_unstage(
18534        &self,
18535        stage: bool,
18536        buffer_id: BufferId,
18537        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18538        cx: &mut App,
18539    ) -> Option<()> {
18540        let project = self.project()?;
18541        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18542        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18543        let buffer_snapshot = buffer.read(cx).snapshot();
18544        let file_exists = buffer_snapshot
18545            .file()
18546            .is_some_and(|file| file.disk_state().exists());
18547        diff.update(cx, |diff, cx| {
18548            diff.stage_or_unstage_hunks(
18549                stage,
18550                &hunks
18551                    .map(|hunk| buffer_diff::DiffHunk {
18552                        buffer_range: hunk.buffer_range,
18553                        diff_base_byte_range: hunk.diff_base_byte_range,
18554                        secondary_status: hunk.secondary_status,
18555                        range: Point::zero()..Point::zero(), // unused
18556                    })
18557                    .collect::<Vec<_>>(),
18558                &buffer_snapshot,
18559                file_exists,
18560                cx,
18561            )
18562        });
18563        None
18564    }
18565
18566    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18567        let ranges: Vec<_> = self
18568            .selections
18569            .disjoint_anchors()
18570            .iter()
18571            .map(|s| s.range())
18572            .collect();
18573        self.buffer
18574            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18575    }
18576
18577    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18578        self.buffer.update(cx, |buffer, cx| {
18579            let ranges = vec![Anchor::min()..Anchor::max()];
18580            if !buffer.all_diff_hunks_expanded()
18581                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18582            {
18583                buffer.collapse_diff_hunks(ranges, cx);
18584                true
18585            } else {
18586                false
18587            }
18588        })
18589    }
18590
18591    fn toggle_diff_hunks_in_ranges(
18592        &mut self,
18593        ranges: Vec<Range<Anchor>>,
18594        cx: &mut Context<Editor>,
18595    ) {
18596        self.buffer.update(cx, |buffer, cx| {
18597            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18598            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18599        })
18600    }
18601
18602    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18603        self.buffer.update(cx, |buffer, cx| {
18604            let snapshot = buffer.snapshot(cx);
18605            let excerpt_id = range.end.excerpt_id;
18606            let point_range = range.to_point(&snapshot);
18607            let expand = !buffer.single_hunk_is_expanded(range, cx);
18608            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18609        })
18610    }
18611
18612    pub(crate) fn apply_all_diff_hunks(
18613        &mut self,
18614        _: &ApplyAllDiffHunks,
18615        window: &mut Window,
18616        cx: &mut Context<Self>,
18617    ) {
18618        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18619
18620        let buffers = self.buffer.read(cx).all_buffers();
18621        for branch_buffer in buffers {
18622            branch_buffer.update(cx, |branch_buffer, cx| {
18623                branch_buffer.merge_into_base(Vec::new(), cx);
18624            });
18625        }
18626
18627        if let Some(project) = self.project.clone() {
18628            self.save(
18629                SaveOptions {
18630                    format: true,
18631                    autosave: false,
18632                },
18633                project,
18634                window,
18635                cx,
18636            )
18637            .detach_and_log_err(cx);
18638        }
18639    }
18640
18641    pub(crate) fn apply_selected_diff_hunks(
18642        &mut self,
18643        _: &ApplyDiffHunk,
18644        window: &mut Window,
18645        cx: &mut Context<Self>,
18646    ) {
18647        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18648        let snapshot = self.snapshot(window, cx);
18649        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18650        let mut ranges_by_buffer = HashMap::default();
18651        self.transact(window, cx, |editor, _window, cx| {
18652            for hunk in hunks {
18653                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18654                    ranges_by_buffer
18655                        .entry(buffer.clone())
18656                        .or_insert_with(Vec::new)
18657                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18658                }
18659            }
18660
18661            for (buffer, ranges) in ranges_by_buffer {
18662                buffer.update(cx, |buffer, cx| {
18663                    buffer.merge_into_base(ranges, cx);
18664                });
18665            }
18666        });
18667
18668        if let Some(project) = self.project.clone() {
18669            self.save(
18670                SaveOptions {
18671                    format: true,
18672                    autosave: false,
18673                },
18674                project,
18675                window,
18676                cx,
18677            )
18678            .detach_and_log_err(cx);
18679        }
18680    }
18681
18682    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18683        if hovered != self.gutter_hovered {
18684            self.gutter_hovered = hovered;
18685            cx.notify();
18686        }
18687    }
18688
18689    pub fn insert_blocks(
18690        &mut self,
18691        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18692        autoscroll: Option<Autoscroll>,
18693        cx: &mut Context<Self>,
18694    ) -> Vec<CustomBlockId> {
18695        let blocks = self
18696            .display_map
18697            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18698        if let Some(autoscroll) = autoscroll {
18699            self.request_autoscroll(autoscroll, cx);
18700        }
18701        cx.notify();
18702        blocks
18703    }
18704
18705    pub fn resize_blocks(
18706        &mut self,
18707        heights: HashMap<CustomBlockId, u32>,
18708        autoscroll: Option<Autoscroll>,
18709        cx: &mut Context<Self>,
18710    ) {
18711        self.display_map
18712            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18713        if let Some(autoscroll) = autoscroll {
18714            self.request_autoscroll(autoscroll, cx);
18715        }
18716        cx.notify();
18717    }
18718
18719    pub fn replace_blocks(
18720        &mut self,
18721        renderers: HashMap<CustomBlockId, RenderBlock>,
18722        autoscroll: Option<Autoscroll>,
18723        cx: &mut Context<Self>,
18724    ) {
18725        self.display_map
18726            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18727        if let Some(autoscroll) = autoscroll {
18728            self.request_autoscroll(autoscroll, cx);
18729        }
18730        cx.notify();
18731    }
18732
18733    pub fn remove_blocks(
18734        &mut self,
18735        block_ids: HashSet<CustomBlockId>,
18736        autoscroll: Option<Autoscroll>,
18737        cx: &mut Context<Self>,
18738    ) {
18739        self.display_map.update(cx, |display_map, cx| {
18740            display_map.remove_blocks(block_ids, cx)
18741        });
18742        if let Some(autoscroll) = autoscroll {
18743            self.request_autoscroll(autoscroll, cx);
18744        }
18745        cx.notify();
18746    }
18747
18748    pub fn row_for_block(
18749        &self,
18750        block_id: CustomBlockId,
18751        cx: &mut Context<Self>,
18752    ) -> Option<DisplayRow> {
18753        self.display_map
18754            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18755    }
18756
18757    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18758        self.focused_block = Some(focused_block);
18759    }
18760
18761    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18762        self.focused_block.take()
18763    }
18764
18765    pub fn insert_creases(
18766        &mut self,
18767        creases: impl IntoIterator<Item = Crease<Anchor>>,
18768        cx: &mut Context<Self>,
18769    ) -> Vec<CreaseId> {
18770        self.display_map
18771            .update(cx, |map, cx| map.insert_creases(creases, cx))
18772    }
18773
18774    pub fn remove_creases(
18775        &mut self,
18776        ids: impl IntoIterator<Item = CreaseId>,
18777        cx: &mut Context<Self>,
18778    ) -> Vec<(CreaseId, Range<Anchor>)> {
18779        self.display_map
18780            .update(cx, |map, cx| map.remove_creases(ids, cx))
18781    }
18782
18783    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18784        self.display_map
18785            .update(cx, |map, cx| map.snapshot(cx))
18786            .longest_row()
18787    }
18788
18789    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18790        self.display_map
18791            .update(cx, |map, cx| map.snapshot(cx))
18792            .max_point()
18793    }
18794
18795    pub fn text(&self, cx: &App) -> String {
18796        self.buffer.read(cx).read(cx).text()
18797    }
18798
18799    pub fn is_empty(&self, cx: &App) -> bool {
18800        self.buffer.read(cx).read(cx).is_empty()
18801    }
18802
18803    pub fn text_option(&self, cx: &App) -> Option<String> {
18804        let text = self.text(cx);
18805        let text = text.trim();
18806
18807        if text.is_empty() {
18808            return None;
18809        }
18810
18811        Some(text.to_string())
18812    }
18813
18814    pub fn set_text(
18815        &mut self,
18816        text: impl Into<Arc<str>>,
18817        window: &mut Window,
18818        cx: &mut Context<Self>,
18819    ) {
18820        self.transact(window, cx, |this, _, cx| {
18821            this.buffer
18822                .read(cx)
18823                .as_singleton()
18824                .expect("you can only call set_text on editors for singleton buffers")
18825                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18826        });
18827    }
18828
18829    pub fn display_text(&self, cx: &mut App) -> String {
18830        self.display_map
18831            .update(cx, |map, cx| map.snapshot(cx))
18832            .text()
18833    }
18834
18835    fn create_minimap(
18836        &self,
18837        minimap_settings: MinimapSettings,
18838        window: &mut Window,
18839        cx: &mut Context<Self>,
18840    ) -> Option<Entity<Self>> {
18841        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18842            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18843    }
18844
18845    fn initialize_new_minimap(
18846        &self,
18847        minimap_settings: MinimapSettings,
18848        window: &mut Window,
18849        cx: &mut Context<Self>,
18850    ) -> Entity<Self> {
18851        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18852
18853        let mut minimap = Editor::new_internal(
18854            EditorMode::Minimap {
18855                parent: cx.weak_entity(),
18856            },
18857            self.buffer.clone(),
18858            None,
18859            Some(self.display_map.clone()),
18860            window,
18861            cx,
18862        );
18863        minimap.scroll_manager.clone_state(&self.scroll_manager);
18864        minimap.set_text_style_refinement(TextStyleRefinement {
18865            font_size: Some(MINIMAP_FONT_SIZE),
18866            font_weight: Some(MINIMAP_FONT_WEIGHT),
18867            ..Default::default()
18868        });
18869        minimap.update_minimap_configuration(minimap_settings, cx);
18870        cx.new(|_| minimap)
18871    }
18872
18873    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18874        let current_line_highlight = minimap_settings
18875            .current_line_highlight
18876            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18877        self.set_current_line_highlight(Some(current_line_highlight));
18878    }
18879
18880    pub fn minimap(&self) -> Option<&Entity<Self>> {
18881        self.minimap
18882            .as_ref()
18883            .filter(|_| self.minimap_visibility.visible())
18884    }
18885
18886    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18887        let mut wrap_guides = smallvec![];
18888
18889        if self.show_wrap_guides == Some(false) {
18890            return wrap_guides;
18891        }
18892
18893        let settings = self.buffer.read(cx).language_settings(cx);
18894        if settings.show_wrap_guides {
18895            match self.soft_wrap_mode(cx) {
18896                SoftWrap::Column(soft_wrap) => {
18897                    wrap_guides.push((soft_wrap as usize, true));
18898                }
18899                SoftWrap::Bounded(soft_wrap) => {
18900                    wrap_guides.push((soft_wrap as usize, true));
18901                }
18902                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18903            }
18904            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18905        }
18906
18907        wrap_guides
18908    }
18909
18910    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18911        let settings = self.buffer.read(cx).language_settings(cx);
18912        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18913        match mode {
18914            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18915                SoftWrap::None
18916            }
18917            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18918            language_settings::SoftWrap::PreferredLineLength => {
18919                SoftWrap::Column(settings.preferred_line_length)
18920            }
18921            language_settings::SoftWrap::Bounded => {
18922                SoftWrap::Bounded(settings.preferred_line_length)
18923            }
18924        }
18925    }
18926
18927    pub fn set_soft_wrap_mode(
18928        &mut self,
18929        mode: language_settings::SoftWrap,
18930
18931        cx: &mut Context<Self>,
18932    ) {
18933        self.soft_wrap_mode_override = Some(mode);
18934        cx.notify();
18935    }
18936
18937    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18938        self.hard_wrap = hard_wrap;
18939        cx.notify();
18940    }
18941
18942    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18943        self.text_style_refinement = Some(style);
18944    }
18945
18946    /// called by the Element so we know what style we were most recently rendered with.
18947    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
18948        // We intentionally do not inform the display map about the minimap style
18949        // so that wrapping is not recalculated and stays consistent for the editor
18950        // and its linked minimap.
18951        if !self.mode.is_minimap() {
18952            let font = style.text.font();
18953            let font_size = style.text.font_size.to_pixels(window.rem_size());
18954            let display_map = self
18955                .placeholder_display_map
18956                .as_ref()
18957                .filter(|_| self.is_empty(cx))
18958                .unwrap_or(&self.display_map);
18959
18960            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
18961        }
18962        self.style = Some(style);
18963    }
18964
18965    pub fn style(&self) -> Option<&EditorStyle> {
18966        self.style.as_ref()
18967    }
18968
18969    // Called by the element. This method is not designed to be called outside of the editor
18970    // element's layout code because it does not notify when rewrapping is computed synchronously.
18971    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18972        if self.is_empty(cx) {
18973            self.placeholder_display_map
18974                .as_ref()
18975                .map_or(false, |display_map| {
18976                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
18977                })
18978        } else {
18979            self.display_map
18980                .update(cx, |map, cx| map.set_wrap_width(width, cx))
18981        }
18982    }
18983
18984    pub fn set_soft_wrap(&mut self) {
18985        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18986    }
18987
18988    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18989        if self.soft_wrap_mode_override.is_some() {
18990            self.soft_wrap_mode_override.take();
18991        } else {
18992            let soft_wrap = match self.soft_wrap_mode(cx) {
18993                SoftWrap::GitDiff => return,
18994                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18995                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18996                    language_settings::SoftWrap::None
18997                }
18998            };
18999            self.soft_wrap_mode_override = Some(soft_wrap);
19000        }
19001        cx.notify();
19002    }
19003
19004    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19005        let Some(workspace) = self.workspace() else {
19006            return;
19007        };
19008        let fs = workspace.read(cx).app_state().fs.clone();
19009        let current_show = TabBarSettings::get_global(cx).show;
19010        update_settings_file(fs, cx, move |setting, _| {
19011            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19012        });
19013    }
19014
19015    pub fn toggle_indent_guides(
19016        &mut self,
19017        _: &ToggleIndentGuides,
19018        _: &mut Window,
19019        cx: &mut Context<Self>,
19020    ) {
19021        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19022            self.buffer
19023                .read(cx)
19024                .language_settings(cx)
19025                .indent_guides
19026                .enabled
19027        });
19028        self.show_indent_guides = Some(!currently_enabled);
19029        cx.notify();
19030    }
19031
19032    fn should_show_indent_guides(&self) -> Option<bool> {
19033        self.show_indent_guides
19034    }
19035
19036    pub fn toggle_line_numbers(
19037        &mut self,
19038        _: &ToggleLineNumbers,
19039        _: &mut Window,
19040        cx: &mut Context<Self>,
19041    ) {
19042        let mut editor_settings = EditorSettings::get_global(cx).clone();
19043        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19044        EditorSettings::override_global(editor_settings, cx);
19045    }
19046
19047    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19048        if let Some(show_line_numbers) = self.show_line_numbers {
19049            return show_line_numbers;
19050        }
19051        EditorSettings::get_global(cx).gutter.line_numbers
19052    }
19053
19054    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19055        self.use_relative_line_numbers
19056            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19057    }
19058
19059    pub fn toggle_relative_line_numbers(
19060        &mut self,
19061        _: &ToggleRelativeLineNumbers,
19062        _: &mut Window,
19063        cx: &mut Context<Self>,
19064    ) {
19065        let is_relative = self.should_use_relative_line_numbers(cx);
19066        self.set_relative_line_number(Some(!is_relative), cx)
19067    }
19068
19069    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19070        self.use_relative_line_numbers = is_relative;
19071        cx.notify();
19072    }
19073
19074    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19075        self.show_gutter = show_gutter;
19076        cx.notify();
19077    }
19078
19079    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19080        self.show_scrollbars = ScrollbarAxes {
19081            horizontal: show,
19082            vertical: show,
19083        };
19084        cx.notify();
19085    }
19086
19087    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19088        self.show_scrollbars.vertical = show;
19089        cx.notify();
19090    }
19091
19092    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19093        self.show_scrollbars.horizontal = show;
19094        cx.notify();
19095    }
19096
19097    pub fn set_minimap_visibility(
19098        &mut self,
19099        minimap_visibility: MinimapVisibility,
19100        window: &mut Window,
19101        cx: &mut Context<Self>,
19102    ) {
19103        if self.minimap_visibility != minimap_visibility {
19104            if minimap_visibility.visible() && self.minimap.is_none() {
19105                let minimap_settings = EditorSettings::get_global(cx).minimap;
19106                self.minimap =
19107                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19108            }
19109            self.minimap_visibility = minimap_visibility;
19110            cx.notify();
19111        }
19112    }
19113
19114    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19115        self.set_show_scrollbars(false, cx);
19116        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19117    }
19118
19119    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19120        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19121    }
19122
19123    /// Normally the text in full mode and auto height editors is padded on the
19124    /// left side by roughly half a character width for improved hit testing.
19125    ///
19126    /// Use this method to disable this for cases where this is not wanted (e.g.
19127    /// if you want to align the editor text with some other text above or below)
19128    /// or if you want to add this padding to single-line editors.
19129    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19130        self.offset_content = offset_content;
19131        cx.notify();
19132    }
19133
19134    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19135        self.show_line_numbers = Some(show_line_numbers);
19136        cx.notify();
19137    }
19138
19139    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19140        self.disable_expand_excerpt_buttons = true;
19141        cx.notify();
19142    }
19143
19144    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19145        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19146        cx.notify();
19147    }
19148
19149    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19150        self.show_code_actions = Some(show_code_actions);
19151        cx.notify();
19152    }
19153
19154    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19155        self.show_runnables = Some(show_runnables);
19156        cx.notify();
19157    }
19158
19159    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19160        self.show_breakpoints = Some(show_breakpoints);
19161        cx.notify();
19162    }
19163
19164    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19165        if self.display_map.read(cx).masked != masked {
19166            self.display_map.update(cx, |map, _| map.masked = masked);
19167        }
19168        cx.notify()
19169    }
19170
19171    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19172        self.show_wrap_guides = Some(show_wrap_guides);
19173        cx.notify();
19174    }
19175
19176    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19177        self.show_indent_guides = Some(show_indent_guides);
19178        cx.notify();
19179    }
19180
19181    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19182        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19183            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19184                && let Some(dir) = file.abs_path(cx).parent()
19185            {
19186                return Some(dir.to_owned());
19187            }
19188
19189            if let Some(project_path) = buffer.read(cx).project_path(cx) {
19190                return Some(project_path.path.to_path_buf());
19191            }
19192        }
19193
19194        None
19195    }
19196
19197    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19198        self.active_excerpt(cx)?
19199            .1
19200            .read(cx)
19201            .file()
19202            .and_then(|f| f.as_local())
19203    }
19204
19205    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19206        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19207            let buffer = buffer.read(cx);
19208            if let Some(project_path) = buffer.project_path(cx) {
19209                let project = self.project()?.read(cx);
19210                project.absolute_path(&project_path, cx)
19211            } else {
19212                buffer
19213                    .file()
19214                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19215            }
19216        })
19217    }
19218
19219    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19220        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19221            let project_path = buffer.read(cx).project_path(cx)?;
19222            let project = self.project()?.read(cx);
19223            let entry = project.entry_for_path(&project_path, cx)?;
19224            let path = entry.path.to_path_buf();
19225            Some(path)
19226        })
19227    }
19228
19229    pub fn reveal_in_finder(
19230        &mut self,
19231        _: &RevealInFileManager,
19232        _window: &mut Window,
19233        cx: &mut Context<Self>,
19234    ) {
19235        if let Some(target) = self.target_file(cx) {
19236            cx.reveal_path(&target.abs_path(cx));
19237        }
19238    }
19239
19240    pub fn copy_path(
19241        &mut self,
19242        _: &zed_actions::workspace::CopyPath,
19243        _window: &mut Window,
19244        cx: &mut Context<Self>,
19245    ) {
19246        if let Some(path) = self.target_file_abs_path(cx)
19247            && let Some(path) = path.to_str()
19248        {
19249            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19250        }
19251    }
19252
19253    pub fn copy_relative_path(
19254        &mut self,
19255        _: &zed_actions::workspace::CopyRelativePath,
19256        _window: &mut Window,
19257        cx: &mut Context<Self>,
19258    ) {
19259        if let Some(path) = self.target_file_path(cx)
19260            && let Some(path) = path.to_str()
19261        {
19262            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19263        }
19264    }
19265
19266    /// Returns the project path for the editor's buffer, if any buffer is
19267    /// opened in the editor.
19268    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19269        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19270            buffer.read(cx).project_path(cx)
19271        } else {
19272            None
19273        }
19274    }
19275
19276    // Returns true if the editor handled a go-to-line request
19277    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19278        maybe!({
19279            let breakpoint_store = self.breakpoint_store.as_ref()?;
19280
19281            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19282            else {
19283                self.clear_row_highlights::<ActiveDebugLine>();
19284                return None;
19285            };
19286
19287            let position = active_stack_frame.position;
19288            let buffer_id = position.buffer_id?;
19289            let snapshot = self
19290                .project
19291                .as_ref()?
19292                .read(cx)
19293                .buffer_for_id(buffer_id, cx)?
19294                .read(cx)
19295                .snapshot();
19296
19297            let mut handled = false;
19298            for (id, ExcerptRange { context, .. }) in
19299                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19300            {
19301                if context.start.cmp(&position, &snapshot).is_ge()
19302                    || context.end.cmp(&position, &snapshot).is_lt()
19303                {
19304                    continue;
19305                }
19306                let snapshot = self.buffer.read(cx).snapshot(cx);
19307                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19308
19309                handled = true;
19310                self.clear_row_highlights::<ActiveDebugLine>();
19311
19312                self.go_to_line::<ActiveDebugLine>(
19313                    multibuffer_anchor,
19314                    Some(cx.theme().colors().editor_debugger_active_line_background),
19315                    window,
19316                    cx,
19317                );
19318
19319                cx.notify();
19320            }
19321
19322            handled.then_some(())
19323        })
19324        .is_some()
19325    }
19326
19327    pub fn copy_file_name_without_extension(
19328        &mut self,
19329        _: &CopyFileNameWithoutExtension,
19330        _: &mut Window,
19331        cx: &mut Context<Self>,
19332    ) {
19333        if let Some(file) = self.target_file(cx)
19334            && let Some(file_stem) = file.path().file_stem()
19335            && let Some(name) = file_stem.to_str()
19336        {
19337            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19338        }
19339    }
19340
19341    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19342        if let Some(file) = self.target_file(cx)
19343            && let Some(file_name) = file.path().file_name()
19344            && let Some(name) = file_name.to_str()
19345        {
19346            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19347        }
19348    }
19349
19350    pub fn toggle_git_blame(
19351        &mut self,
19352        _: &::git::Blame,
19353        window: &mut Window,
19354        cx: &mut Context<Self>,
19355    ) {
19356        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19357
19358        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19359            self.start_git_blame(true, window, cx);
19360        }
19361
19362        cx.notify();
19363    }
19364
19365    pub fn toggle_git_blame_inline(
19366        &mut self,
19367        _: &ToggleGitBlameInline,
19368        window: &mut Window,
19369        cx: &mut Context<Self>,
19370    ) {
19371        self.toggle_git_blame_inline_internal(true, window, cx);
19372        cx.notify();
19373    }
19374
19375    pub fn open_git_blame_commit(
19376        &mut self,
19377        _: &OpenGitBlameCommit,
19378        window: &mut Window,
19379        cx: &mut Context<Self>,
19380    ) {
19381        self.open_git_blame_commit_internal(window, cx);
19382    }
19383
19384    fn open_git_blame_commit_internal(
19385        &mut self,
19386        window: &mut Window,
19387        cx: &mut Context<Self>,
19388    ) -> Option<()> {
19389        let blame = self.blame.as_ref()?;
19390        let snapshot = self.snapshot(window, cx);
19391        let cursor = self.selections.newest::<Point>(cx).head();
19392        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19393        let (_, blame_entry) = blame
19394            .update(cx, |blame, cx| {
19395                blame
19396                    .blame_for_rows(
19397                        &[RowInfo {
19398                            buffer_id: Some(buffer.remote_id()),
19399                            buffer_row: Some(point.row),
19400                            ..Default::default()
19401                        }],
19402                        cx,
19403                    )
19404                    .next()
19405            })
19406            .flatten()?;
19407        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19408        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19409        let workspace = self.workspace()?.downgrade();
19410        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19411        None
19412    }
19413
19414    pub fn git_blame_inline_enabled(&self) -> bool {
19415        self.git_blame_inline_enabled
19416    }
19417
19418    pub fn toggle_selection_menu(
19419        &mut self,
19420        _: &ToggleSelectionMenu,
19421        _: &mut Window,
19422        cx: &mut Context<Self>,
19423    ) {
19424        self.show_selection_menu = self
19425            .show_selection_menu
19426            .map(|show_selections_menu| !show_selections_menu)
19427            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19428
19429        cx.notify();
19430    }
19431
19432    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19433        self.show_selection_menu
19434            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19435    }
19436
19437    fn start_git_blame(
19438        &mut self,
19439        user_triggered: bool,
19440        window: &mut Window,
19441        cx: &mut Context<Self>,
19442    ) {
19443        if let Some(project) = self.project() {
19444            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19445                && buffer.read(cx).file().is_none()
19446            {
19447                return;
19448            }
19449
19450            let focused = self.focus_handle(cx).contains_focused(window, cx);
19451
19452            let project = project.clone();
19453            let blame = cx
19454                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19455            self.blame_subscription =
19456                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19457            self.blame = Some(blame);
19458        }
19459    }
19460
19461    fn toggle_git_blame_inline_internal(
19462        &mut self,
19463        user_triggered: bool,
19464        window: &mut Window,
19465        cx: &mut Context<Self>,
19466    ) {
19467        if self.git_blame_inline_enabled {
19468            self.git_blame_inline_enabled = false;
19469            self.show_git_blame_inline = false;
19470            self.show_git_blame_inline_delay_task.take();
19471        } else {
19472            self.git_blame_inline_enabled = true;
19473            self.start_git_blame_inline(user_triggered, window, cx);
19474        }
19475
19476        cx.notify();
19477    }
19478
19479    fn start_git_blame_inline(
19480        &mut self,
19481        user_triggered: bool,
19482        window: &mut Window,
19483        cx: &mut Context<Self>,
19484    ) {
19485        self.start_git_blame(user_triggered, window, cx);
19486
19487        if ProjectSettings::get_global(cx)
19488            .git
19489            .inline_blame_delay()
19490            .is_some()
19491        {
19492            self.start_inline_blame_timer(window, cx);
19493        } else {
19494            self.show_git_blame_inline = true
19495        }
19496    }
19497
19498    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19499        self.blame.as_ref()
19500    }
19501
19502    pub fn show_git_blame_gutter(&self) -> bool {
19503        self.show_git_blame_gutter
19504    }
19505
19506    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19507        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19508    }
19509
19510    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19511        self.show_git_blame_inline
19512            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19513            && !self.newest_selection_head_on_empty_line(cx)
19514            && self.has_blame_entries(cx)
19515    }
19516
19517    fn has_blame_entries(&self, cx: &App) -> bool {
19518        self.blame()
19519            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19520    }
19521
19522    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19523        let cursor_anchor = self.selections.newest_anchor().head();
19524
19525        let snapshot = self.buffer.read(cx).snapshot(cx);
19526        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19527
19528        snapshot.line_len(buffer_row) == 0
19529    }
19530
19531    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19532        let buffer_and_selection = maybe!({
19533            let selection = self.selections.newest::<Point>(cx);
19534            let selection_range = selection.range();
19535
19536            let multi_buffer = self.buffer().read(cx);
19537            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19538            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19539
19540            let (buffer, range, _) = if selection.reversed {
19541                buffer_ranges.first()
19542            } else {
19543                buffer_ranges.last()
19544            }?;
19545
19546            let selection = text::ToPoint::to_point(&range.start, buffer).row
19547                ..text::ToPoint::to_point(&range.end, buffer).row;
19548            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19549        });
19550
19551        let Some((buffer, selection)) = buffer_and_selection else {
19552            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19553        };
19554
19555        let Some(project) = self.project() else {
19556            return Task::ready(Err(anyhow!("editor does not have project")));
19557        };
19558
19559        project.update(cx, |project, cx| {
19560            project.get_permalink_to_line(&buffer, selection, cx)
19561        })
19562    }
19563
19564    pub fn copy_permalink_to_line(
19565        &mut self,
19566        _: &CopyPermalinkToLine,
19567        window: &mut Window,
19568        cx: &mut Context<Self>,
19569    ) {
19570        let permalink_task = self.get_permalink_to_line(cx);
19571        let workspace = self.workspace();
19572
19573        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19574            Ok(permalink) => {
19575                cx.update(|_, cx| {
19576                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19577                })
19578                .ok();
19579            }
19580            Err(err) => {
19581                let message = format!("Failed to copy permalink: {err}");
19582
19583                anyhow::Result::<()>::Err(err).log_err();
19584
19585                if let Some(workspace) = workspace {
19586                    workspace
19587                        .update_in(cx, |workspace, _, cx| {
19588                            struct CopyPermalinkToLine;
19589
19590                            workspace.show_toast(
19591                                Toast::new(
19592                                    NotificationId::unique::<CopyPermalinkToLine>(),
19593                                    message,
19594                                ),
19595                                cx,
19596                            )
19597                        })
19598                        .ok();
19599                }
19600            }
19601        })
19602        .detach();
19603    }
19604
19605    pub fn copy_file_location(
19606        &mut self,
19607        _: &CopyFileLocation,
19608        _: &mut Window,
19609        cx: &mut Context<Self>,
19610    ) {
19611        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19612        if let Some(file) = self.target_file(cx)
19613            && let Some(path) = file.path().to_str()
19614        {
19615            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19616        }
19617    }
19618
19619    pub fn open_permalink_to_line(
19620        &mut self,
19621        _: &OpenPermalinkToLine,
19622        window: &mut Window,
19623        cx: &mut Context<Self>,
19624    ) {
19625        let permalink_task = self.get_permalink_to_line(cx);
19626        let workspace = self.workspace();
19627
19628        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19629            Ok(permalink) => {
19630                cx.update(|_, cx| {
19631                    cx.open_url(permalink.as_ref());
19632                })
19633                .ok();
19634            }
19635            Err(err) => {
19636                let message = format!("Failed to open permalink: {err}");
19637
19638                anyhow::Result::<()>::Err(err).log_err();
19639
19640                if let Some(workspace) = workspace {
19641                    workspace
19642                        .update(cx, |workspace, cx| {
19643                            struct OpenPermalinkToLine;
19644
19645                            workspace.show_toast(
19646                                Toast::new(
19647                                    NotificationId::unique::<OpenPermalinkToLine>(),
19648                                    message,
19649                                ),
19650                                cx,
19651                            )
19652                        })
19653                        .ok();
19654                }
19655            }
19656        })
19657        .detach();
19658    }
19659
19660    pub fn insert_uuid_v4(
19661        &mut self,
19662        _: &InsertUuidV4,
19663        window: &mut Window,
19664        cx: &mut Context<Self>,
19665    ) {
19666        self.insert_uuid(UuidVersion::V4, window, cx);
19667    }
19668
19669    pub fn insert_uuid_v7(
19670        &mut self,
19671        _: &InsertUuidV7,
19672        window: &mut Window,
19673        cx: &mut Context<Self>,
19674    ) {
19675        self.insert_uuid(UuidVersion::V7, window, cx);
19676    }
19677
19678    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19679        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19680        self.transact(window, cx, |this, window, cx| {
19681            let edits = this
19682                .selections
19683                .all::<Point>(cx)
19684                .into_iter()
19685                .map(|selection| {
19686                    let uuid = match version {
19687                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19688                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19689                    };
19690
19691                    (selection.range(), uuid.to_string())
19692                });
19693            this.edit(edits, cx);
19694            this.refresh_edit_prediction(true, false, window, cx);
19695        });
19696    }
19697
19698    pub fn open_selections_in_multibuffer(
19699        &mut self,
19700        _: &OpenSelectionsInMultibuffer,
19701        window: &mut Window,
19702        cx: &mut Context<Self>,
19703    ) {
19704        let multibuffer = self.buffer.read(cx);
19705
19706        let Some(buffer) = multibuffer.as_singleton() else {
19707            return;
19708        };
19709
19710        let Some(workspace) = self.workspace() else {
19711            return;
19712        };
19713
19714        let title = multibuffer.title(cx).to_string();
19715
19716        let locations = self
19717            .selections
19718            .all_anchors(cx)
19719            .iter()
19720            .map(|selection| Location {
19721                buffer: buffer.clone(),
19722                range: selection.start.text_anchor..selection.end.text_anchor,
19723            })
19724            .collect::<Vec<_>>();
19725
19726        cx.spawn_in(window, async move |_, cx| {
19727            workspace.update_in(cx, |workspace, window, cx| {
19728                Self::open_locations_in_multibuffer(
19729                    workspace,
19730                    locations,
19731                    format!("Selections for '{title}'"),
19732                    false,
19733                    MultibufferSelectionMode::All,
19734                    window,
19735                    cx,
19736                );
19737            })
19738        })
19739        .detach();
19740    }
19741
19742    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19743    /// last highlight added will be used.
19744    ///
19745    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19746    pub fn highlight_rows<T: 'static>(
19747        &mut self,
19748        range: Range<Anchor>,
19749        color: Hsla,
19750        options: RowHighlightOptions,
19751        cx: &mut Context<Self>,
19752    ) {
19753        let snapshot = self.buffer().read(cx).snapshot(cx);
19754        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19755        let ix = row_highlights.binary_search_by(|highlight| {
19756            Ordering::Equal
19757                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19758                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19759        });
19760
19761        if let Err(mut ix) = ix {
19762            let index = post_inc(&mut self.highlight_order);
19763
19764            // If this range intersects with the preceding highlight, then merge it with
19765            // the preceding highlight. Otherwise insert a new highlight.
19766            let mut merged = false;
19767            if ix > 0 {
19768                let prev_highlight = &mut row_highlights[ix - 1];
19769                if prev_highlight
19770                    .range
19771                    .end
19772                    .cmp(&range.start, &snapshot)
19773                    .is_ge()
19774                {
19775                    ix -= 1;
19776                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19777                        prev_highlight.range.end = range.end;
19778                    }
19779                    merged = true;
19780                    prev_highlight.index = index;
19781                    prev_highlight.color = color;
19782                    prev_highlight.options = options;
19783                }
19784            }
19785
19786            if !merged {
19787                row_highlights.insert(
19788                    ix,
19789                    RowHighlight {
19790                        range,
19791                        index,
19792                        color,
19793                        options,
19794                        type_id: TypeId::of::<T>(),
19795                    },
19796                );
19797            }
19798
19799            // If any of the following highlights intersect with this one, merge them.
19800            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19801                let highlight = &row_highlights[ix];
19802                if next_highlight
19803                    .range
19804                    .start
19805                    .cmp(&highlight.range.end, &snapshot)
19806                    .is_le()
19807                {
19808                    if next_highlight
19809                        .range
19810                        .end
19811                        .cmp(&highlight.range.end, &snapshot)
19812                        .is_gt()
19813                    {
19814                        row_highlights[ix].range.end = next_highlight.range.end;
19815                    }
19816                    row_highlights.remove(ix + 1);
19817                } else {
19818                    break;
19819                }
19820            }
19821        }
19822    }
19823
19824    /// Remove any highlighted row ranges of the given type that intersect the
19825    /// given ranges.
19826    pub fn remove_highlighted_rows<T: 'static>(
19827        &mut self,
19828        ranges_to_remove: Vec<Range<Anchor>>,
19829        cx: &mut Context<Self>,
19830    ) {
19831        let snapshot = self.buffer().read(cx).snapshot(cx);
19832        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19833        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19834        row_highlights.retain(|highlight| {
19835            while let Some(range_to_remove) = ranges_to_remove.peek() {
19836                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19837                    Ordering::Less | Ordering::Equal => {
19838                        ranges_to_remove.next();
19839                    }
19840                    Ordering::Greater => {
19841                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19842                            Ordering::Less | Ordering::Equal => {
19843                                return false;
19844                            }
19845                            Ordering::Greater => break,
19846                        }
19847                    }
19848                }
19849            }
19850
19851            true
19852        })
19853    }
19854
19855    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19856    pub fn clear_row_highlights<T: 'static>(&mut self) {
19857        self.highlighted_rows.remove(&TypeId::of::<T>());
19858    }
19859
19860    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19861    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19862        self.highlighted_rows
19863            .get(&TypeId::of::<T>())
19864            .map_or(&[] as &[_], |vec| vec.as_slice())
19865            .iter()
19866            .map(|highlight| (highlight.range.clone(), highlight.color))
19867    }
19868
19869    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19870    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19871    /// Allows to ignore certain kinds of highlights.
19872    pub fn highlighted_display_rows(
19873        &self,
19874        window: &mut Window,
19875        cx: &mut App,
19876    ) -> BTreeMap<DisplayRow, LineHighlight> {
19877        let snapshot = self.snapshot(window, cx);
19878        let mut used_highlight_orders = HashMap::default();
19879        self.highlighted_rows
19880            .iter()
19881            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19882            .fold(
19883                BTreeMap::<DisplayRow, LineHighlight>::new(),
19884                |mut unique_rows, highlight| {
19885                    let start = highlight.range.start.to_display_point(&snapshot);
19886                    let end = highlight.range.end.to_display_point(&snapshot);
19887                    let start_row = start.row().0;
19888                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19889                        && end.column() == 0
19890                    {
19891                        end.row().0.saturating_sub(1)
19892                    } else {
19893                        end.row().0
19894                    };
19895                    for row in start_row..=end_row {
19896                        let used_index =
19897                            used_highlight_orders.entry(row).or_insert(highlight.index);
19898                        if highlight.index >= *used_index {
19899                            *used_index = highlight.index;
19900                            unique_rows.insert(
19901                                DisplayRow(row),
19902                                LineHighlight {
19903                                    include_gutter: highlight.options.include_gutter,
19904                                    border: None,
19905                                    background: highlight.color.into(),
19906                                    type_id: Some(highlight.type_id),
19907                                },
19908                            );
19909                        }
19910                    }
19911                    unique_rows
19912                },
19913            )
19914    }
19915
19916    pub fn highlighted_display_row_for_autoscroll(
19917        &self,
19918        snapshot: &DisplaySnapshot,
19919    ) -> Option<DisplayRow> {
19920        self.highlighted_rows
19921            .values()
19922            .flat_map(|highlighted_rows| highlighted_rows.iter())
19923            .filter_map(|highlight| {
19924                if highlight.options.autoscroll {
19925                    Some(highlight.range.start.to_display_point(snapshot).row())
19926                } else {
19927                    None
19928                }
19929            })
19930            .min()
19931    }
19932
19933    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19934        self.highlight_background::<SearchWithinRange>(
19935            ranges,
19936            |colors| colors.colors().editor_document_highlight_read_background,
19937            cx,
19938        )
19939    }
19940
19941    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19942        self.breadcrumb_header = Some(new_header);
19943    }
19944
19945    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19946        self.clear_background_highlights::<SearchWithinRange>(cx);
19947    }
19948
19949    pub fn highlight_background<T: 'static>(
19950        &mut self,
19951        ranges: &[Range<Anchor>],
19952        color_fetcher: fn(&Theme) -> Hsla,
19953        cx: &mut Context<Self>,
19954    ) {
19955        self.background_highlights.insert(
19956            HighlightKey::Type(TypeId::of::<T>()),
19957            (color_fetcher, Arc::from(ranges)),
19958        );
19959        self.scrollbar_marker_state.dirty = true;
19960        cx.notify();
19961    }
19962
19963    pub fn highlight_background_key<T: 'static>(
19964        &mut self,
19965        key: usize,
19966        ranges: &[Range<Anchor>],
19967        color_fetcher: fn(&Theme) -> Hsla,
19968        cx: &mut Context<Self>,
19969    ) {
19970        self.background_highlights.insert(
19971            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19972            (color_fetcher, Arc::from(ranges)),
19973        );
19974        self.scrollbar_marker_state.dirty = true;
19975        cx.notify();
19976    }
19977
19978    pub fn clear_background_highlights<T: 'static>(
19979        &mut self,
19980        cx: &mut Context<Self>,
19981    ) -> Option<BackgroundHighlight> {
19982        let text_highlights = self
19983            .background_highlights
19984            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19985        if !text_highlights.1.is_empty() {
19986            self.scrollbar_marker_state.dirty = true;
19987            cx.notify();
19988        }
19989        Some(text_highlights)
19990    }
19991
19992    pub fn highlight_gutter<T: 'static>(
19993        &mut self,
19994        ranges: impl Into<Vec<Range<Anchor>>>,
19995        color_fetcher: fn(&App) -> Hsla,
19996        cx: &mut Context<Self>,
19997    ) {
19998        self.gutter_highlights
19999            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20000        cx.notify();
20001    }
20002
20003    pub fn clear_gutter_highlights<T: 'static>(
20004        &mut self,
20005        cx: &mut Context<Self>,
20006    ) -> Option<GutterHighlight> {
20007        cx.notify();
20008        self.gutter_highlights.remove(&TypeId::of::<T>())
20009    }
20010
20011    pub fn insert_gutter_highlight<T: 'static>(
20012        &mut self,
20013        range: Range<Anchor>,
20014        color_fetcher: fn(&App) -> Hsla,
20015        cx: &mut Context<Self>,
20016    ) {
20017        let snapshot = self.buffer().read(cx).snapshot(cx);
20018        let mut highlights = self
20019            .gutter_highlights
20020            .remove(&TypeId::of::<T>())
20021            .map(|(_, highlights)| highlights)
20022            .unwrap_or_default();
20023        let ix = highlights.binary_search_by(|highlight| {
20024            Ordering::Equal
20025                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20026                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20027        });
20028        if let Err(ix) = ix {
20029            highlights.insert(ix, range);
20030        }
20031        self.gutter_highlights
20032            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20033    }
20034
20035    pub fn remove_gutter_highlights<T: 'static>(
20036        &mut self,
20037        ranges_to_remove: Vec<Range<Anchor>>,
20038        cx: &mut Context<Self>,
20039    ) {
20040        let snapshot = self.buffer().read(cx).snapshot(cx);
20041        let Some((color_fetcher, mut gutter_highlights)) =
20042            self.gutter_highlights.remove(&TypeId::of::<T>())
20043        else {
20044            return;
20045        };
20046        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20047        gutter_highlights.retain(|highlight| {
20048            while let Some(range_to_remove) = ranges_to_remove.peek() {
20049                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20050                    Ordering::Less | Ordering::Equal => {
20051                        ranges_to_remove.next();
20052                    }
20053                    Ordering::Greater => {
20054                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20055                            Ordering::Less | Ordering::Equal => {
20056                                return false;
20057                            }
20058                            Ordering::Greater => break,
20059                        }
20060                    }
20061                }
20062            }
20063
20064            true
20065        });
20066        self.gutter_highlights
20067            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20068    }
20069
20070    #[cfg(feature = "test-support")]
20071    pub fn all_text_highlights(
20072        &self,
20073        window: &mut Window,
20074        cx: &mut Context<Self>,
20075    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20076        let snapshot = self.snapshot(window, cx);
20077        self.display_map.update(cx, |display_map, _| {
20078            display_map
20079                .all_text_highlights()
20080                .map(|highlight| {
20081                    let (style, ranges) = highlight.as_ref();
20082                    (
20083                        *style,
20084                        ranges
20085                            .iter()
20086                            .map(|range| range.clone().to_display_points(&snapshot))
20087                            .collect(),
20088                    )
20089                })
20090                .collect()
20091        })
20092    }
20093
20094    #[cfg(feature = "test-support")]
20095    pub fn all_text_background_highlights(
20096        &self,
20097        window: &mut Window,
20098        cx: &mut Context<Self>,
20099    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20100        let snapshot = self.snapshot(window, cx);
20101        let buffer = &snapshot.buffer_snapshot;
20102        let start = buffer.anchor_before(0);
20103        let end = buffer.anchor_after(buffer.len());
20104        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20105    }
20106
20107    #[cfg(any(test, feature = "test-support"))]
20108    pub fn sorted_background_highlights_in_range(
20109        &self,
20110        search_range: Range<Anchor>,
20111        display_snapshot: &DisplaySnapshot,
20112        theme: &Theme,
20113    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20114        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20115        res.sort_by(|a, b| {
20116            a.0.start
20117                .cmp(&b.0.start)
20118                .then_with(|| a.0.end.cmp(&b.0.end))
20119                .then_with(|| a.1.cmp(&b.1))
20120        });
20121        res
20122    }
20123
20124    #[cfg(feature = "test-support")]
20125    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20126        let snapshot = self.buffer().read(cx).snapshot(cx);
20127
20128        let highlights = self
20129            .background_highlights
20130            .get(&HighlightKey::Type(TypeId::of::<
20131                items::BufferSearchHighlights,
20132            >()));
20133
20134        if let Some((_color, ranges)) = highlights {
20135            ranges
20136                .iter()
20137                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20138                .collect_vec()
20139        } else {
20140            vec![]
20141        }
20142    }
20143
20144    fn document_highlights_for_position<'a>(
20145        &'a self,
20146        position: Anchor,
20147        buffer: &'a MultiBufferSnapshot,
20148    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20149        let read_highlights = self
20150            .background_highlights
20151            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20152            .map(|h| &h.1);
20153        let write_highlights = self
20154            .background_highlights
20155            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20156            .map(|h| &h.1);
20157        let left_position = position.bias_left(buffer);
20158        let right_position = position.bias_right(buffer);
20159        read_highlights
20160            .into_iter()
20161            .chain(write_highlights)
20162            .flat_map(move |ranges| {
20163                let start_ix = match ranges.binary_search_by(|probe| {
20164                    let cmp = probe.end.cmp(&left_position, buffer);
20165                    if cmp.is_ge() {
20166                        Ordering::Greater
20167                    } else {
20168                        Ordering::Less
20169                    }
20170                }) {
20171                    Ok(i) | Err(i) => i,
20172                };
20173
20174                ranges[start_ix..]
20175                    .iter()
20176                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20177            })
20178    }
20179
20180    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20181        self.background_highlights
20182            .get(&HighlightKey::Type(TypeId::of::<T>()))
20183            .is_some_and(|(_, highlights)| !highlights.is_empty())
20184    }
20185
20186    /// Returns all background highlights for a given range.
20187    ///
20188    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20189    pub fn background_highlights_in_range(
20190        &self,
20191        search_range: Range<Anchor>,
20192        display_snapshot: &DisplaySnapshot,
20193        theme: &Theme,
20194    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20195        let mut results = Vec::new();
20196        for (color_fetcher, ranges) in self.background_highlights.values() {
20197            let color = color_fetcher(theme);
20198            let start_ix = match ranges.binary_search_by(|probe| {
20199                let cmp = probe
20200                    .end
20201                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20202                if cmp.is_gt() {
20203                    Ordering::Greater
20204                } else {
20205                    Ordering::Less
20206                }
20207            }) {
20208                Ok(i) | Err(i) => i,
20209            };
20210            for range in &ranges[start_ix..] {
20211                if range
20212                    .start
20213                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20214                    .is_ge()
20215                {
20216                    break;
20217                }
20218
20219                let start = range.start.to_display_point(display_snapshot);
20220                let end = range.end.to_display_point(display_snapshot);
20221                results.push((start..end, color))
20222            }
20223        }
20224        results
20225    }
20226
20227    pub fn gutter_highlights_in_range(
20228        &self,
20229        search_range: Range<Anchor>,
20230        display_snapshot: &DisplaySnapshot,
20231        cx: &App,
20232    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20233        let mut results = Vec::new();
20234        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20235            let color = color_fetcher(cx);
20236            let start_ix = match ranges.binary_search_by(|probe| {
20237                let cmp = probe
20238                    .end
20239                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20240                if cmp.is_gt() {
20241                    Ordering::Greater
20242                } else {
20243                    Ordering::Less
20244                }
20245            }) {
20246                Ok(i) | Err(i) => i,
20247            };
20248            for range in &ranges[start_ix..] {
20249                if range
20250                    .start
20251                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20252                    .is_ge()
20253                {
20254                    break;
20255                }
20256
20257                let start = range.start.to_display_point(display_snapshot);
20258                let end = range.end.to_display_point(display_snapshot);
20259                results.push((start..end, color))
20260            }
20261        }
20262        results
20263    }
20264
20265    /// Get the text ranges corresponding to the redaction query
20266    pub fn redacted_ranges(
20267        &self,
20268        search_range: Range<Anchor>,
20269        display_snapshot: &DisplaySnapshot,
20270        cx: &App,
20271    ) -> Vec<Range<DisplayPoint>> {
20272        display_snapshot
20273            .buffer_snapshot
20274            .redacted_ranges(search_range, |file| {
20275                if let Some(file) = file {
20276                    file.is_private()
20277                        && EditorSettings::get(
20278                            Some(SettingsLocation {
20279                                worktree_id: file.worktree_id(cx),
20280                                path: file.path().as_ref(),
20281                            }),
20282                            cx,
20283                        )
20284                        .redact_private_values
20285                } else {
20286                    false
20287                }
20288            })
20289            .map(|range| {
20290                range.start.to_display_point(display_snapshot)
20291                    ..range.end.to_display_point(display_snapshot)
20292            })
20293            .collect()
20294    }
20295
20296    pub fn highlight_text_key<T: 'static>(
20297        &mut self,
20298        key: usize,
20299        ranges: Vec<Range<Anchor>>,
20300        style: HighlightStyle,
20301        cx: &mut Context<Self>,
20302    ) {
20303        self.display_map.update(cx, |map, _| {
20304            map.highlight_text(
20305                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20306                ranges,
20307                style,
20308            );
20309        });
20310        cx.notify();
20311    }
20312
20313    pub fn highlight_text<T: 'static>(
20314        &mut self,
20315        ranges: Vec<Range<Anchor>>,
20316        style: HighlightStyle,
20317        cx: &mut Context<Self>,
20318    ) {
20319        self.display_map.update(cx, |map, _| {
20320            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20321        });
20322        cx.notify();
20323    }
20324
20325    pub(crate) fn highlight_inlays<T: 'static>(
20326        &mut self,
20327        highlights: Vec<InlayHighlight>,
20328        style: HighlightStyle,
20329        cx: &mut Context<Self>,
20330    ) {
20331        self.display_map.update(cx, |map, _| {
20332            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20333        });
20334        cx.notify();
20335    }
20336
20337    pub fn text_highlights<'a, T: 'static>(
20338        &'a self,
20339        cx: &'a App,
20340    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20341        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20342    }
20343
20344    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20345        let cleared = self
20346            .display_map
20347            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20348        if cleared {
20349            cx.notify();
20350        }
20351    }
20352
20353    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20354        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20355            && self.focus_handle.is_focused(window)
20356    }
20357
20358    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20359        self.show_cursor_when_unfocused = is_enabled;
20360        cx.notify();
20361    }
20362
20363    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20364        cx.notify();
20365    }
20366
20367    fn on_debug_session_event(
20368        &mut self,
20369        _session: Entity<Session>,
20370        event: &SessionEvent,
20371        cx: &mut Context<Self>,
20372    ) {
20373        if let SessionEvent::InvalidateInlineValue = event {
20374            self.refresh_inline_values(cx);
20375        }
20376    }
20377
20378    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20379        let Some(project) = self.project.clone() else {
20380            return;
20381        };
20382
20383        if !self.inline_value_cache.enabled {
20384            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20385            self.splice_inlays(&inlays, Vec::new(), cx);
20386            return;
20387        }
20388
20389        let current_execution_position = self
20390            .highlighted_rows
20391            .get(&TypeId::of::<ActiveDebugLine>())
20392            .and_then(|lines| lines.last().map(|line| line.range.end));
20393
20394        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20395            let inline_values = editor
20396                .update(cx, |editor, cx| {
20397                    let Some(current_execution_position) = current_execution_position else {
20398                        return Some(Task::ready(Ok(Vec::new())));
20399                    };
20400
20401                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20402                        let snapshot = buffer.snapshot(cx);
20403
20404                        let excerpt = snapshot.excerpt_containing(
20405                            current_execution_position..current_execution_position,
20406                        )?;
20407
20408                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20409                    })?;
20410
20411                    let range =
20412                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20413
20414                    project.inline_values(buffer, range, cx)
20415                })
20416                .ok()
20417                .flatten()?
20418                .await
20419                .context("refreshing debugger inlays")
20420                .log_err()?;
20421
20422            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20423
20424            for (buffer_id, inline_value) in inline_values
20425                .into_iter()
20426                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20427            {
20428                buffer_inline_values
20429                    .entry(buffer_id)
20430                    .or_default()
20431                    .push(inline_value);
20432            }
20433
20434            editor
20435                .update(cx, |editor, cx| {
20436                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20437                    let mut new_inlays = Vec::default();
20438
20439                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20440                        let buffer_id = buffer_snapshot.remote_id();
20441                        buffer_inline_values
20442                            .get(&buffer_id)
20443                            .into_iter()
20444                            .flatten()
20445                            .for_each(|hint| {
20446                                let inlay = Inlay::debugger(
20447                                    post_inc(&mut editor.next_inlay_id),
20448                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20449                                    hint.text(),
20450                                );
20451                                if !inlay.text.chars().contains(&'\n') {
20452                                    new_inlays.push(inlay);
20453                                }
20454                            });
20455                    }
20456
20457                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20458                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20459
20460                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20461                })
20462                .ok()?;
20463            Some(())
20464        });
20465    }
20466
20467    fn on_buffer_event(
20468        &mut self,
20469        multibuffer: &Entity<MultiBuffer>,
20470        event: &multi_buffer::Event,
20471        window: &mut Window,
20472        cx: &mut Context<Self>,
20473    ) {
20474        match event {
20475            multi_buffer::Event::Edited {
20476                singleton_buffer_edited,
20477                edited_buffer,
20478            } => {
20479                self.scrollbar_marker_state.dirty = true;
20480                self.active_indent_guides_state.dirty = true;
20481                self.refresh_active_diagnostics(cx);
20482                self.refresh_code_actions(window, cx);
20483                self.refresh_selected_text_highlights(true, window, cx);
20484                self.refresh_single_line_folds(window, cx);
20485                refresh_matching_bracket_highlights(self, window, cx);
20486                if self.has_active_edit_prediction() {
20487                    self.update_visible_edit_prediction(window, cx);
20488                }
20489                if let Some(project) = self.project.as_ref()
20490                    && let Some(edited_buffer) = edited_buffer
20491                {
20492                    project.update(cx, |project, cx| {
20493                        self.registered_buffers
20494                            .entry(edited_buffer.read(cx).remote_id())
20495                            .or_insert_with(|| {
20496                                project.register_buffer_with_language_servers(edited_buffer, cx)
20497                            });
20498                    });
20499                }
20500                cx.emit(EditorEvent::BufferEdited);
20501                cx.emit(SearchEvent::MatchesInvalidated);
20502
20503                if let Some(buffer) = edited_buffer {
20504                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20505                }
20506
20507                if *singleton_buffer_edited {
20508                    if let Some(buffer) = edited_buffer
20509                        && buffer.read(cx).file().is_none()
20510                    {
20511                        cx.emit(EditorEvent::TitleChanged);
20512                    }
20513                    if let Some(project) = &self.project {
20514                        #[allow(clippy::mutable_key_type)]
20515                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20516                            multibuffer
20517                                .all_buffers()
20518                                .into_iter()
20519                                .filter_map(|buffer| {
20520                                    buffer.update(cx, |buffer, cx| {
20521                                        let language = buffer.language()?;
20522                                        let should_discard = project.update(cx, |project, cx| {
20523                                            project.is_local()
20524                                                && !project.has_language_servers_for(buffer, cx)
20525                                        });
20526                                        should_discard.not().then_some(language.clone())
20527                                    })
20528                                })
20529                                .collect::<HashSet<_>>()
20530                        });
20531                        if !languages_affected.is_empty() {
20532                            self.refresh_inlay_hints(
20533                                InlayHintRefreshReason::BufferEdited(languages_affected),
20534                                cx,
20535                            );
20536                        }
20537                    }
20538                }
20539
20540                let Some(project) = &self.project else { return };
20541                let (telemetry, is_via_ssh) = {
20542                    let project = project.read(cx);
20543                    let telemetry = project.client().telemetry().clone();
20544                    let is_via_ssh = project.is_via_remote_server();
20545                    (telemetry, is_via_ssh)
20546                };
20547                refresh_linked_ranges(self, window, cx);
20548                telemetry.log_edit_event("editor", is_via_ssh);
20549            }
20550            multi_buffer::Event::ExcerptsAdded {
20551                buffer,
20552                predecessor,
20553                excerpts,
20554            } => {
20555                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20556                let buffer_id = buffer.read(cx).remote_id();
20557                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20558                    && let Some(project) = &self.project
20559                {
20560                    update_uncommitted_diff_for_buffer(
20561                        cx.entity(),
20562                        project,
20563                        [buffer.clone()],
20564                        self.buffer.clone(),
20565                        cx,
20566                    )
20567                    .detach();
20568                }
20569                if self.active_diagnostics != ActiveDiagnostic::All {
20570                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20571                }
20572                cx.emit(EditorEvent::ExcerptsAdded {
20573                    buffer: buffer.clone(),
20574                    predecessor: *predecessor,
20575                    excerpts: excerpts.clone(),
20576                });
20577                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20578            }
20579            multi_buffer::Event::ExcerptsRemoved {
20580                ids,
20581                removed_buffer_ids,
20582            } => {
20583                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20584                let buffer = self.buffer.read(cx);
20585                self.registered_buffers
20586                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20587                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20588                cx.emit(EditorEvent::ExcerptsRemoved {
20589                    ids: ids.clone(),
20590                    removed_buffer_ids: removed_buffer_ids.clone(),
20591                });
20592            }
20593            multi_buffer::Event::ExcerptsEdited {
20594                excerpt_ids,
20595                buffer_ids,
20596            } => {
20597                self.display_map.update(cx, |map, cx| {
20598                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20599                });
20600                cx.emit(EditorEvent::ExcerptsEdited {
20601                    ids: excerpt_ids.clone(),
20602                });
20603            }
20604            multi_buffer::Event::ExcerptsExpanded { ids } => {
20605                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20606                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20607            }
20608            multi_buffer::Event::Reparsed(buffer_id) => {
20609                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20610                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20611
20612                cx.emit(EditorEvent::Reparsed(*buffer_id));
20613            }
20614            multi_buffer::Event::DiffHunksToggled => {
20615                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20616            }
20617            multi_buffer::Event::LanguageChanged(buffer_id) => {
20618                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20619                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20620                cx.emit(EditorEvent::Reparsed(*buffer_id));
20621                cx.notify();
20622            }
20623            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20624            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20625            multi_buffer::Event::FileHandleChanged
20626            | multi_buffer::Event::Reloaded
20627            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20628            multi_buffer::Event::DiagnosticsUpdated => {
20629                self.update_diagnostics_state(window, cx);
20630            }
20631            _ => {}
20632        };
20633    }
20634
20635    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20636        if !self.diagnostics_enabled() {
20637            return;
20638        }
20639        self.refresh_active_diagnostics(cx);
20640        self.refresh_inline_diagnostics(true, window, cx);
20641        self.scrollbar_marker_state.dirty = true;
20642        cx.notify();
20643    }
20644
20645    pub fn start_temporary_diff_override(&mut self) {
20646        self.load_diff_task.take();
20647        self.temporary_diff_override = true;
20648    }
20649
20650    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20651        self.temporary_diff_override = false;
20652        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20653        self.buffer.update(cx, |buffer, cx| {
20654            buffer.set_all_diff_hunks_collapsed(cx);
20655        });
20656
20657        if let Some(project) = self.project.clone() {
20658            self.load_diff_task = Some(
20659                update_uncommitted_diff_for_buffer(
20660                    cx.entity(),
20661                    &project,
20662                    self.buffer.read(cx).all_buffers(),
20663                    self.buffer.clone(),
20664                    cx,
20665                )
20666                .shared(),
20667            );
20668        }
20669    }
20670
20671    fn on_display_map_changed(
20672        &mut self,
20673        _: Entity<DisplayMap>,
20674        _: &mut Window,
20675        cx: &mut Context<Self>,
20676    ) {
20677        cx.notify();
20678    }
20679
20680    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20681        if self.diagnostics_enabled() {
20682            let new_severity = EditorSettings::get_global(cx)
20683                .diagnostics_max_severity
20684                .unwrap_or(DiagnosticSeverity::Hint);
20685            self.set_max_diagnostics_severity(new_severity, cx);
20686        }
20687        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20688        self.update_edit_prediction_settings(cx);
20689        self.refresh_edit_prediction(true, false, window, cx);
20690        self.refresh_inline_values(cx);
20691        self.refresh_inlay_hints(
20692            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20693                self.selections.newest_anchor().head(),
20694                &self.buffer.read(cx).snapshot(cx),
20695                cx,
20696            )),
20697            cx,
20698        );
20699
20700        let old_cursor_shape = self.cursor_shape;
20701        let old_show_breadcrumbs = self.show_breadcrumbs;
20702
20703        {
20704            let editor_settings = EditorSettings::get_global(cx);
20705            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20706            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20707            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20708            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20709        }
20710
20711        if old_cursor_shape != self.cursor_shape {
20712            cx.emit(EditorEvent::CursorShapeChanged);
20713        }
20714
20715        if old_show_breadcrumbs != self.show_breadcrumbs {
20716            cx.emit(EditorEvent::BreadcrumbsChanged);
20717        }
20718
20719        let project_settings = ProjectSettings::get_global(cx);
20720        self.serialize_dirty_buffers =
20721            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20722
20723        if self.mode.is_full() {
20724            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20725            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20726            if self.show_inline_diagnostics != show_inline_diagnostics {
20727                self.show_inline_diagnostics = show_inline_diagnostics;
20728                self.refresh_inline_diagnostics(false, window, cx);
20729            }
20730
20731            if self.git_blame_inline_enabled != inline_blame_enabled {
20732                self.toggle_git_blame_inline_internal(false, window, cx);
20733            }
20734
20735            let minimap_settings = EditorSettings::get_global(cx).minimap;
20736            if self.minimap_visibility != MinimapVisibility::Disabled {
20737                if self.minimap_visibility.settings_visibility()
20738                    != minimap_settings.minimap_enabled()
20739                {
20740                    self.set_minimap_visibility(
20741                        MinimapVisibility::for_mode(self.mode(), cx),
20742                        window,
20743                        cx,
20744                    );
20745                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20746                    minimap_entity.update(cx, |minimap_editor, cx| {
20747                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20748                    })
20749                }
20750            }
20751        }
20752
20753        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20754            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20755        }) {
20756            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20757                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20758            }
20759            self.refresh_colors(false, None, window, cx);
20760        }
20761
20762        cx.notify();
20763    }
20764
20765    pub fn set_searchable(&mut self, searchable: bool) {
20766        self.searchable = searchable;
20767    }
20768
20769    pub fn searchable(&self) -> bool {
20770        self.searchable
20771    }
20772
20773    fn open_proposed_changes_editor(
20774        &mut self,
20775        _: &OpenProposedChangesEditor,
20776        window: &mut Window,
20777        cx: &mut Context<Self>,
20778    ) {
20779        let Some(workspace) = self.workspace() else {
20780            cx.propagate();
20781            return;
20782        };
20783
20784        let selections = self.selections.all::<usize>(cx);
20785        let multi_buffer = self.buffer.read(cx);
20786        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20787        let mut new_selections_by_buffer = HashMap::default();
20788        for selection in selections {
20789            for (buffer, range, _) in
20790                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20791            {
20792                let mut range = range.to_point(buffer);
20793                range.start.column = 0;
20794                range.end.column = buffer.line_len(range.end.row);
20795                new_selections_by_buffer
20796                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20797                    .or_insert(Vec::new())
20798                    .push(range)
20799            }
20800        }
20801
20802        let proposed_changes_buffers = new_selections_by_buffer
20803            .into_iter()
20804            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20805            .collect::<Vec<_>>();
20806        let proposed_changes_editor = cx.new(|cx| {
20807            ProposedChangesEditor::new(
20808                "Proposed changes",
20809                proposed_changes_buffers,
20810                self.project.clone(),
20811                window,
20812                cx,
20813            )
20814        });
20815
20816        window.defer(cx, move |window, cx| {
20817            workspace.update(cx, |workspace, cx| {
20818                workspace.active_pane().update(cx, |pane, cx| {
20819                    pane.add_item(
20820                        Box::new(proposed_changes_editor),
20821                        true,
20822                        true,
20823                        None,
20824                        window,
20825                        cx,
20826                    );
20827                });
20828            });
20829        });
20830    }
20831
20832    pub fn open_excerpts_in_split(
20833        &mut self,
20834        _: &OpenExcerptsSplit,
20835        window: &mut Window,
20836        cx: &mut Context<Self>,
20837    ) {
20838        self.open_excerpts_common(None, true, window, cx)
20839    }
20840
20841    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20842        self.open_excerpts_common(None, false, window, cx)
20843    }
20844
20845    fn open_excerpts_common(
20846        &mut self,
20847        jump_data: Option<JumpData>,
20848        split: bool,
20849        window: &mut Window,
20850        cx: &mut Context<Self>,
20851    ) {
20852        let Some(workspace) = self.workspace() else {
20853            cx.propagate();
20854            return;
20855        };
20856
20857        if self.buffer.read(cx).is_singleton() {
20858            cx.propagate();
20859            return;
20860        }
20861
20862        let mut new_selections_by_buffer = HashMap::default();
20863        match &jump_data {
20864            Some(JumpData::MultiBufferPoint {
20865                excerpt_id,
20866                position,
20867                anchor,
20868                line_offset_from_top,
20869            }) => {
20870                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20871                if let Some(buffer) = multi_buffer_snapshot
20872                    .buffer_id_for_excerpt(*excerpt_id)
20873                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20874                {
20875                    let buffer_snapshot = buffer.read(cx).snapshot();
20876                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20877                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20878                    } else {
20879                        buffer_snapshot.clip_point(*position, Bias::Left)
20880                    };
20881                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20882                    new_selections_by_buffer.insert(
20883                        buffer,
20884                        (
20885                            vec![jump_to_offset..jump_to_offset],
20886                            Some(*line_offset_from_top),
20887                        ),
20888                    );
20889                }
20890            }
20891            Some(JumpData::MultiBufferRow {
20892                row,
20893                line_offset_from_top,
20894            }) => {
20895                let point = MultiBufferPoint::new(row.0, 0);
20896                if let Some((buffer, buffer_point, _)) =
20897                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20898                {
20899                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20900                    new_selections_by_buffer
20901                        .entry(buffer)
20902                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20903                        .0
20904                        .push(buffer_offset..buffer_offset)
20905                }
20906            }
20907            None => {
20908                let selections = self.selections.all::<usize>(cx);
20909                let multi_buffer = self.buffer.read(cx);
20910                for selection in selections {
20911                    for (snapshot, range, _, anchor) in multi_buffer
20912                        .snapshot(cx)
20913                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20914                    {
20915                        if let Some(anchor) = anchor {
20916                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20917                            else {
20918                                continue;
20919                            };
20920                            let offset = text::ToOffset::to_offset(
20921                                &anchor.text_anchor,
20922                                &buffer_handle.read(cx).snapshot(),
20923                            );
20924                            let range = offset..offset;
20925                            new_selections_by_buffer
20926                                .entry(buffer_handle)
20927                                .or_insert((Vec::new(), None))
20928                                .0
20929                                .push(range)
20930                        } else {
20931                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20932                            else {
20933                                continue;
20934                            };
20935                            new_selections_by_buffer
20936                                .entry(buffer_handle)
20937                                .or_insert((Vec::new(), None))
20938                                .0
20939                                .push(range)
20940                        }
20941                    }
20942                }
20943            }
20944        }
20945
20946        new_selections_by_buffer
20947            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20948
20949        if new_selections_by_buffer.is_empty() {
20950            return;
20951        }
20952
20953        // We defer the pane interaction because we ourselves are a workspace item
20954        // and activating a new item causes the pane to call a method on us reentrantly,
20955        // which panics if we're on the stack.
20956        window.defer(cx, move |window, cx| {
20957            workspace.update(cx, |workspace, cx| {
20958                let pane = if split {
20959                    workspace.adjacent_pane(window, cx)
20960                } else {
20961                    workspace.active_pane().clone()
20962                };
20963
20964                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20965                    let editor = buffer
20966                        .read(cx)
20967                        .file()
20968                        .is_none()
20969                        .then(|| {
20970                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20971                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20972                            // Instead, we try to activate the existing editor in the pane first.
20973                            let (editor, pane_item_index) =
20974                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20975                                    let editor = item.downcast::<Editor>()?;
20976                                    let singleton_buffer =
20977                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20978                                    if singleton_buffer == buffer {
20979                                        Some((editor, i))
20980                                    } else {
20981                                        None
20982                                    }
20983                                })?;
20984                            pane.update(cx, |pane, cx| {
20985                                pane.activate_item(pane_item_index, true, true, window, cx)
20986                            });
20987                            Some(editor)
20988                        })
20989                        .flatten()
20990                        .unwrap_or_else(|| {
20991                            workspace.open_project_item::<Self>(
20992                                pane.clone(),
20993                                buffer,
20994                                true,
20995                                true,
20996                                window,
20997                                cx,
20998                            )
20999                        });
21000
21001                    editor.update(cx, |editor, cx| {
21002                        let autoscroll = match scroll_offset {
21003                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21004                            None => Autoscroll::newest(),
21005                        };
21006                        let nav_history = editor.nav_history.take();
21007                        editor.change_selections(
21008                            SelectionEffects::scroll(autoscroll),
21009                            window,
21010                            cx,
21011                            |s| {
21012                                s.select_ranges(ranges);
21013                            },
21014                        );
21015                        editor.nav_history = nav_history;
21016                    });
21017                }
21018            })
21019        });
21020    }
21021
21022    // For now, don't allow opening excerpts in buffers that aren't backed by
21023    // regular project files.
21024    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21025        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21026    }
21027
21028    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21029        let snapshot = self.buffer.read(cx).read(cx);
21030        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21031        Some(
21032            ranges
21033                .iter()
21034                .map(move |range| {
21035                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21036                })
21037                .collect(),
21038        )
21039    }
21040
21041    fn selection_replacement_ranges(
21042        &self,
21043        range: Range<OffsetUtf16>,
21044        cx: &mut App,
21045    ) -> Vec<Range<OffsetUtf16>> {
21046        let selections = self.selections.all::<OffsetUtf16>(cx);
21047        let newest_selection = selections
21048            .iter()
21049            .max_by_key(|selection| selection.id)
21050            .unwrap();
21051        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21052        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21053        let snapshot = self.buffer.read(cx).read(cx);
21054        selections
21055            .into_iter()
21056            .map(|mut selection| {
21057                selection.start.0 =
21058                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21059                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21060                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21061                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21062            })
21063            .collect()
21064    }
21065
21066    fn report_editor_event(
21067        &self,
21068        reported_event: ReportEditorEvent,
21069        file_extension: Option<String>,
21070        cx: &App,
21071    ) {
21072        if cfg!(any(test, feature = "test-support")) {
21073            return;
21074        }
21075
21076        let Some(project) = &self.project else { return };
21077
21078        // If None, we are in a file without an extension
21079        let file = self
21080            .buffer
21081            .read(cx)
21082            .as_singleton()
21083            .and_then(|b| b.read(cx).file());
21084        let file_extension = file_extension.or(file
21085            .as_ref()
21086            .and_then(|file| Path::new(file.file_name(cx)).extension())
21087            .and_then(|e| e.to_str())
21088            .map(|a| a.to_string()));
21089
21090        let vim_mode = vim_enabled(cx);
21091
21092        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21093        let copilot_enabled = edit_predictions_provider
21094            == language::language_settings::EditPredictionProvider::Copilot;
21095        let copilot_enabled_for_language = self
21096            .buffer
21097            .read(cx)
21098            .language_settings(cx)
21099            .show_edit_predictions;
21100
21101        let project = project.read(cx);
21102        let event_type = reported_event.event_type();
21103
21104        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21105            telemetry::event!(
21106                event_type,
21107                type = if auto_saved {"autosave"} else {"manual"},
21108                file_extension,
21109                vim_mode,
21110                copilot_enabled,
21111                copilot_enabled_for_language,
21112                edit_predictions_provider,
21113                is_via_ssh = project.is_via_remote_server(),
21114            );
21115        } else {
21116            telemetry::event!(
21117                event_type,
21118                file_extension,
21119                vim_mode,
21120                copilot_enabled,
21121                copilot_enabled_for_language,
21122                edit_predictions_provider,
21123                is_via_ssh = project.is_via_remote_server(),
21124            );
21125        };
21126    }
21127
21128    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21129    /// with each line being an array of {text, highlight} objects.
21130    fn copy_highlight_json(
21131        &mut self,
21132        _: &CopyHighlightJson,
21133        window: &mut Window,
21134        cx: &mut Context<Self>,
21135    ) {
21136        #[derive(Serialize)]
21137        struct Chunk<'a> {
21138            text: String,
21139            highlight: Option<&'a str>,
21140        }
21141
21142        let snapshot = self.buffer.read(cx).snapshot(cx);
21143        let range = self
21144            .selected_text_range(false, window, cx)
21145            .and_then(|selection| {
21146                if selection.range.is_empty() {
21147                    None
21148                } else {
21149                    Some(selection.range)
21150                }
21151            })
21152            .unwrap_or_else(|| 0..snapshot.len());
21153
21154        let chunks = snapshot.chunks(range, true);
21155        let mut lines = Vec::new();
21156        let mut line: VecDeque<Chunk> = VecDeque::new();
21157
21158        let Some(style) = self.style.as_ref() else {
21159            return;
21160        };
21161
21162        for chunk in chunks {
21163            let highlight = chunk
21164                .syntax_highlight_id
21165                .and_then(|id| id.name(&style.syntax));
21166            let mut chunk_lines = chunk.text.split('\n').peekable();
21167            while let Some(text) = chunk_lines.next() {
21168                let mut merged_with_last_token = false;
21169                if let Some(last_token) = line.back_mut()
21170                    && last_token.highlight == highlight
21171                {
21172                    last_token.text.push_str(text);
21173                    merged_with_last_token = true;
21174                }
21175
21176                if !merged_with_last_token {
21177                    line.push_back(Chunk {
21178                        text: text.into(),
21179                        highlight,
21180                    });
21181                }
21182
21183                if chunk_lines.peek().is_some() {
21184                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21185                        line.pop_front();
21186                    }
21187                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21188                        line.pop_back();
21189                    }
21190
21191                    lines.push(mem::take(&mut line));
21192                }
21193            }
21194        }
21195
21196        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21197            return;
21198        };
21199        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21200    }
21201
21202    pub fn open_context_menu(
21203        &mut self,
21204        _: &OpenContextMenu,
21205        window: &mut Window,
21206        cx: &mut Context<Self>,
21207    ) {
21208        self.request_autoscroll(Autoscroll::newest(), cx);
21209        let position = self.selections.newest_display(cx).start;
21210        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21211    }
21212
21213    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21214        &self.inlay_hint_cache
21215    }
21216
21217    pub fn replay_insert_event(
21218        &mut self,
21219        text: &str,
21220        relative_utf16_range: Option<Range<isize>>,
21221        window: &mut Window,
21222        cx: &mut Context<Self>,
21223    ) {
21224        if !self.input_enabled {
21225            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21226            return;
21227        }
21228        if let Some(relative_utf16_range) = relative_utf16_range {
21229            let selections = self.selections.all::<OffsetUtf16>(cx);
21230            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21231                let new_ranges = selections.into_iter().map(|range| {
21232                    let start = OffsetUtf16(
21233                        range
21234                            .head()
21235                            .0
21236                            .saturating_add_signed(relative_utf16_range.start),
21237                    );
21238                    let end = OffsetUtf16(
21239                        range
21240                            .head()
21241                            .0
21242                            .saturating_add_signed(relative_utf16_range.end),
21243                    );
21244                    start..end
21245                });
21246                s.select_ranges(new_ranges);
21247            });
21248        }
21249
21250        self.handle_input(text, window, cx);
21251    }
21252
21253    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21254        let Some(provider) = self.semantics_provider.as_ref() else {
21255            return false;
21256        };
21257
21258        let mut supports = false;
21259        self.buffer().update(cx, |this, cx| {
21260            this.for_each_buffer(|buffer| {
21261                supports |= provider.supports_inlay_hints(buffer, cx);
21262            });
21263        });
21264
21265        supports
21266    }
21267
21268    pub fn is_focused(&self, window: &Window) -> bool {
21269        self.focus_handle.is_focused(window)
21270    }
21271
21272    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21273        cx.emit(EditorEvent::Focused);
21274
21275        if let Some(descendant) = self
21276            .last_focused_descendant
21277            .take()
21278            .and_then(|descendant| descendant.upgrade())
21279        {
21280            window.focus(&descendant);
21281        } else {
21282            if let Some(blame) = self.blame.as_ref() {
21283                blame.update(cx, GitBlame::focus)
21284            }
21285
21286            self.blink_manager.update(cx, BlinkManager::enable);
21287            self.show_cursor_names(window, cx);
21288            self.buffer.update(cx, |buffer, cx| {
21289                buffer.finalize_last_transaction(cx);
21290                if self.leader_id.is_none() {
21291                    buffer.set_active_selections(
21292                        &self.selections.disjoint_anchors_arc(),
21293                        self.selections.line_mode,
21294                        self.cursor_shape,
21295                        cx,
21296                    );
21297                }
21298            });
21299        }
21300    }
21301
21302    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21303        cx.emit(EditorEvent::FocusedIn)
21304    }
21305
21306    fn handle_focus_out(
21307        &mut self,
21308        event: FocusOutEvent,
21309        _window: &mut Window,
21310        cx: &mut Context<Self>,
21311    ) {
21312        if event.blurred != self.focus_handle {
21313            self.last_focused_descendant = Some(event.blurred);
21314        }
21315        self.selection_drag_state = SelectionDragState::None;
21316        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21317    }
21318
21319    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21320        self.blink_manager.update(cx, BlinkManager::disable);
21321        self.buffer
21322            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21323
21324        if let Some(blame) = self.blame.as_ref() {
21325            blame.update(cx, GitBlame::blur)
21326        }
21327        if !self.hover_state.focused(window, cx) {
21328            hide_hover(self, cx);
21329        }
21330        if !self
21331            .context_menu
21332            .borrow()
21333            .as_ref()
21334            .is_some_and(|context_menu| context_menu.focused(window, cx))
21335        {
21336            self.hide_context_menu(window, cx);
21337        }
21338        self.discard_edit_prediction(false, cx);
21339        cx.emit(EditorEvent::Blurred);
21340        cx.notify();
21341    }
21342
21343    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21344        let mut pending: String = window
21345            .pending_input_keystrokes()
21346            .into_iter()
21347            .flatten()
21348            .filter_map(|keystroke| {
21349                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21350                    keystroke.key_char.clone()
21351                } else {
21352                    None
21353                }
21354            })
21355            .collect();
21356
21357        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21358            pending = "".to_string();
21359        }
21360
21361        let existing_pending = self
21362            .text_highlights::<PendingInput>(cx)
21363            .map(|(_, ranges)| ranges.to_vec());
21364        if existing_pending.is_none() && pending.is_empty() {
21365            return;
21366        }
21367        let transaction =
21368            self.transact(window, cx, |this, window, cx| {
21369                let selections = this.selections.all::<usize>(cx);
21370                let edits = selections
21371                    .iter()
21372                    .map(|selection| (selection.end..selection.end, pending.clone()));
21373                this.edit(edits, cx);
21374                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21375                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21376                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21377                    }));
21378                });
21379                if let Some(existing_ranges) = existing_pending {
21380                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21381                    this.edit(edits, cx);
21382                }
21383            });
21384
21385        let snapshot = self.snapshot(window, cx);
21386        let ranges = self
21387            .selections
21388            .all::<usize>(cx)
21389            .into_iter()
21390            .map(|selection| {
21391                snapshot.buffer_snapshot.anchor_after(selection.end)
21392                    ..snapshot
21393                        .buffer_snapshot
21394                        .anchor_before(selection.end + pending.len())
21395            })
21396            .collect();
21397
21398        if pending.is_empty() {
21399            self.clear_highlights::<PendingInput>(cx);
21400        } else {
21401            self.highlight_text::<PendingInput>(
21402                ranges,
21403                HighlightStyle {
21404                    underline: Some(UnderlineStyle {
21405                        thickness: px(1.),
21406                        color: None,
21407                        wavy: false,
21408                    }),
21409                    ..Default::default()
21410                },
21411                cx,
21412            );
21413        }
21414
21415        self.ime_transaction = self.ime_transaction.or(transaction);
21416        if let Some(transaction) = self.ime_transaction {
21417            self.buffer.update(cx, |buffer, cx| {
21418                buffer.group_until_transaction(transaction, cx);
21419            });
21420        }
21421
21422        if self.text_highlights::<PendingInput>(cx).is_none() {
21423            self.ime_transaction.take();
21424        }
21425    }
21426
21427    pub fn register_action_renderer(
21428        &mut self,
21429        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21430    ) -> Subscription {
21431        let id = self.next_editor_action_id.post_inc();
21432        self.editor_actions
21433            .borrow_mut()
21434            .insert(id, Box::new(listener));
21435
21436        let editor_actions = self.editor_actions.clone();
21437        Subscription::new(move || {
21438            editor_actions.borrow_mut().remove(&id);
21439        })
21440    }
21441
21442    pub fn register_action<A: Action>(
21443        &mut self,
21444        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21445    ) -> Subscription {
21446        let id = self.next_editor_action_id.post_inc();
21447        let listener = Arc::new(listener);
21448        self.editor_actions.borrow_mut().insert(
21449            id,
21450            Box::new(move |_, window, _| {
21451                let listener = listener.clone();
21452                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21453                    let action = action.downcast_ref().unwrap();
21454                    if phase == DispatchPhase::Bubble {
21455                        listener(action, window, cx)
21456                    }
21457                })
21458            }),
21459        );
21460
21461        let editor_actions = self.editor_actions.clone();
21462        Subscription::new(move || {
21463            editor_actions.borrow_mut().remove(&id);
21464        })
21465    }
21466
21467    pub fn file_header_size(&self) -> u32 {
21468        FILE_HEADER_HEIGHT
21469    }
21470
21471    pub fn restore(
21472        &mut self,
21473        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21474        window: &mut Window,
21475        cx: &mut Context<Self>,
21476    ) {
21477        let workspace = self.workspace();
21478        let project = self.project();
21479        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21480            let mut tasks = Vec::new();
21481            for (buffer_id, changes) in revert_changes {
21482                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21483                    buffer.update(cx, |buffer, cx| {
21484                        buffer.edit(
21485                            changes
21486                                .into_iter()
21487                                .map(|(range, text)| (range, text.to_string())),
21488                            None,
21489                            cx,
21490                        );
21491                    });
21492
21493                    if let Some(project) =
21494                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21495                    {
21496                        project.update(cx, |project, cx| {
21497                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21498                        })
21499                    }
21500                }
21501            }
21502            tasks
21503        });
21504        cx.spawn_in(window, async move |_, cx| {
21505            for (buffer, task) in save_tasks {
21506                let result = task.await;
21507                if result.is_err() {
21508                    let Some(path) = buffer
21509                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21510                        .ok()
21511                    else {
21512                        continue;
21513                    };
21514                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21515                        let Some(task) = cx
21516                            .update_window_entity(workspace, |workspace, window, cx| {
21517                                workspace
21518                                    .open_path_preview(path, None, false, false, false, window, cx)
21519                            })
21520                            .ok()
21521                        else {
21522                            continue;
21523                        };
21524                        task.await.log_err();
21525                    }
21526                }
21527            }
21528        })
21529        .detach();
21530        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21531            selections.refresh()
21532        });
21533    }
21534
21535    pub fn to_pixel_point(
21536        &self,
21537        source: multi_buffer::Anchor,
21538        editor_snapshot: &EditorSnapshot,
21539        window: &mut Window,
21540    ) -> Option<gpui::Point<Pixels>> {
21541        let source_point = source.to_display_point(editor_snapshot);
21542        self.display_to_pixel_point(source_point, editor_snapshot, window)
21543    }
21544
21545    pub fn display_to_pixel_point(
21546        &self,
21547        source: DisplayPoint,
21548        editor_snapshot: &EditorSnapshot,
21549        window: &mut Window,
21550    ) -> Option<gpui::Point<Pixels>> {
21551        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21552        let text_layout_details = self.text_layout_details(window);
21553        let scroll_top = text_layout_details
21554            .scroll_anchor
21555            .scroll_position(editor_snapshot)
21556            .y;
21557
21558        if source.row().as_f32() < scroll_top.floor() {
21559            return None;
21560        }
21561        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21562        let source_y = line_height * (source.row().as_f32() - scroll_top);
21563        Some(gpui::Point::new(source_x, source_y))
21564    }
21565
21566    pub fn has_visible_completions_menu(&self) -> bool {
21567        !self.edit_prediction_preview_is_active()
21568            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21569                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21570            })
21571    }
21572
21573    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21574        if self.mode.is_minimap() {
21575            return;
21576        }
21577        self.addons
21578            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21579    }
21580
21581    pub fn unregister_addon<T: Addon>(&mut self) {
21582        self.addons.remove(&std::any::TypeId::of::<T>());
21583    }
21584
21585    pub fn addon<T: Addon>(&self) -> Option<&T> {
21586        let type_id = std::any::TypeId::of::<T>();
21587        self.addons
21588            .get(&type_id)
21589            .and_then(|item| item.to_any().downcast_ref::<T>())
21590    }
21591
21592    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21593        let type_id = std::any::TypeId::of::<T>();
21594        self.addons
21595            .get_mut(&type_id)
21596            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21597    }
21598
21599    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21600        let text_layout_details = self.text_layout_details(window);
21601        let style = &text_layout_details.editor_style;
21602        let font_id = window.text_system().resolve_font(&style.text.font());
21603        let font_size = style.text.font_size.to_pixels(window.rem_size());
21604        let line_height = style.text.line_height_in_pixels(window.rem_size());
21605        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21606        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21607
21608        CharacterDimensions {
21609            em_width,
21610            em_advance,
21611            line_height,
21612        }
21613    }
21614
21615    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21616        self.load_diff_task.clone()
21617    }
21618
21619    fn read_metadata_from_db(
21620        &mut self,
21621        item_id: u64,
21622        workspace_id: WorkspaceId,
21623        window: &mut Window,
21624        cx: &mut Context<Editor>,
21625    ) {
21626        if self.is_singleton(cx)
21627            && !self.mode.is_minimap()
21628            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21629        {
21630            let buffer_snapshot = OnceCell::new();
21631
21632            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21633                && !folds.is_empty()
21634            {
21635                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21636                self.fold_ranges(
21637                    folds
21638                        .into_iter()
21639                        .map(|(start, end)| {
21640                            snapshot.clip_offset(start, Bias::Left)
21641                                ..snapshot.clip_offset(end, Bias::Right)
21642                        })
21643                        .collect(),
21644                    false,
21645                    window,
21646                    cx,
21647                );
21648            }
21649
21650            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21651                && !selections.is_empty()
21652            {
21653                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21654                // skip adding the initial selection to selection history
21655                self.selection_history.mode = SelectionHistoryMode::Skipping;
21656                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21657                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21658                        snapshot.clip_offset(start, Bias::Left)
21659                            ..snapshot.clip_offset(end, Bias::Right)
21660                    }));
21661                });
21662                self.selection_history.mode = SelectionHistoryMode::Normal;
21663            };
21664        }
21665
21666        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21667    }
21668
21669    fn update_lsp_data(
21670        &mut self,
21671        ignore_cache: bool,
21672        for_buffer: Option<BufferId>,
21673        window: &mut Window,
21674        cx: &mut Context<'_, Self>,
21675    ) {
21676        self.pull_diagnostics(for_buffer, window, cx);
21677        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21678    }
21679}
21680
21681// todo(settings_refactor) this should not be!
21682fn vim_enabled(cx: &App) -> bool {
21683    cx.global::<SettingsStore>()
21684        .raw_user_settings()
21685        .and_then(|settings| settings.content.vim_mode)
21686        == Some(true)
21687}
21688
21689fn process_completion_for_edit(
21690    completion: &Completion,
21691    intent: CompletionIntent,
21692    buffer: &Entity<Buffer>,
21693    cursor_position: &text::Anchor,
21694    cx: &mut Context<Editor>,
21695) -> CompletionEdit {
21696    let buffer = buffer.read(cx);
21697    let buffer_snapshot = buffer.snapshot();
21698    let (snippet, new_text) = if completion.is_snippet() {
21699        // Workaround for typescript language server issues so that methods don't expand within
21700        // strings and functions with type expressions. The previous point is used because the query
21701        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21702        let mut snippet_source = completion.new_text.clone();
21703        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21704        previous_point.column = previous_point.column.saturating_sub(1);
21705        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21706            && scope.prefers_label_for_snippet_in_completion()
21707            && let Some(label) = completion.label()
21708            && matches!(
21709                completion.kind(),
21710                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21711            )
21712        {
21713            snippet_source = label;
21714        }
21715        match Snippet::parse(&snippet_source).log_err() {
21716            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21717            None => (None, completion.new_text.clone()),
21718        }
21719    } else {
21720        (None, completion.new_text.clone())
21721    };
21722
21723    let mut range_to_replace = {
21724        let replace_range = &completion.replace_range;
21725        if let CompletionSource::Lsp {
21726            insert_range: Some(insert_range),
21727            ..
21728        } = &completion.source
21729        {
21730            debug_assert_eq!(
21731                insert_range.start, replace_range.start,
21732                "insert_range and replace_range should start at the same position"
21733            );
21734            debug_assert!(
21735                insert_range
21736                    .start
21737                    .cmp(cursor_position, &buffer_snapshot)
21738                    .is_le(),
21739                "insert_range should start before or at cursor position"
21740            );
21741            debug_assert!(
21742                replace_range
21743                    .start
21744                    .cmp(cursor_position, &buffer_snapshot)
21745                    .is_le(),
21746                "replace_range should start before or at cursor position"
21747            );
21748
21749            let should_replace = match intent {
21750                CompletionIntent::CompleteWithInsert => false,
21751                CompletionIntent::CompleteWithReplace => true,
21752                CompletionIntent::Complete | CompletionIntent::Compose => {
21753                    let insert_mode =
21754                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21755                            .completions
21756                            .lsp_insert_mode;
21757                    match insert_mode {
21758                        LspInsertMode::Insert => false,
21759                        LspInsertMode::Replace => true,
21760                        LspInsertMode::ReplaceSubsequence => {
21761                            let mut text_to_replace = buffer.chars_for_range(
21762                                buffer.anchor_before(replace_range.start)
21763                                    ..buffer.anchor_after(replace_range.end),
21764                            );
21765                            let mut current_needle = text_to_replace.next();
21766                            for haystack_ch in completion.label.text.chars() {
21767                                if let Some(needle_ch) = current_needle
21768                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21769                                {
21770                                    current_needle = text_to_replace.next();
21771                                }
21772                            }
21773                            current_needle.is_none()
21774                        }
21775                        LspInsertMode::ReplaceSuffix => {
21776                            if replace_range
21777                                .end
21778                                .cmp(cursor_position, &buffer_snapshot)
21779                                .is_gt()
21780                            {
21781                                let range_after_cursor = *cursor_position..replace_range.end;
21782                                let text_after_cursor = buffer
21783                                    .text_for_range(
21784                                        buffer.anchor_before(range_after_cursor.start)
21785                                            ..buffer.anchor_after(range_after_cursor.end),
21786                                    )
21787                                    .collect::<String>()
21788                                    .to_ascii_lowercase();
21789                                completion
21790                                    .label
21791                                    .text
21792                                    .to_ascii_lowercase()
21793                                    .ends_with(&text_after_cursor)
21794                            } else {
21795                                true
21796                            }
21797                        }
21798                    }
21799                }
21800            };
21801
21802            if should_replace {
21803                replace_range.clone()
21804            } else {
21805                insert_range.clone()
21806            }
21807        } else {
21808            replace_range.clone()
21809        }
21810    };
21811
21812    if range_to_replace
21813        .end
21814        .cmp(cursor_position, &buffer_snapshot)
21815        .is_lt()
21816    {
21817        range_to_replace.end = *cursor_position;
21818    }
21819
21820    CompletionEdit {
21821        new_text,
21822        replace_range: range_to_replace.to_offset(buffer),
21823        snippet,
21824    }
21825}
21826
21827struct CompletionEdit {
21828    new_text: String,
21829    replace_range: Range<usize>,
21830    snippet: Option<Snippet>,
21831}
21832
21833fn insert_extra_newline_brackets(
21834    buffer: &MultiBufferSnapshot,
21835    range: Range<usize>,
21836    language: &language::LanguageScope,
21837) -> bool {
21838    let leading_whitespace_len = buffer
21839        .reversed_chars_at(range.start)
21840        .take_while(|c| c.is_whitespace() && *c != '\n')
21841        .map(|c| c.len_utf8())
21842        .sum::<usize>();
21843    let trailing_whitespace_len = buffer
21844        .chars_at(range.end)
21845        .take_while(|c| c.is_whitespace() && *c != '\n')
21846        .map(|c| c.len_utf8())
21847        .sum::<usize>();
21848    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21849
21850    language.brackets().any(|(pair, enabled)| {
21851        let pair_start = pair.start.trim_end();
21852        let pair_end = pair.end.trim_start();
21853
21854        enabled
21855            && pair.newline
21856            && buffer.contains_str_at(range.end, pair_end)
21857            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21858    })
21859}
21860
21861fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21862    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21863        [(buffer, range, _)] => (*buffer, range.clone()),
21864        _ => return false,
21865    };
21866    let pair = {
21867        let mut result: Option<BracketMatch> = None;
21868
21869        for pair in buffer
21870            .all_bracket_ranges(range.clone())
21871            .filter(move |pair| {
21872                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21873            })
21874        {
21875            let len = pair.close_range.end - pair.open_range.start;
21876
21877            if let Some(existing) = &result {
21878                let existing_len = existing.close_range.end - existing.open_range.start;
21879                if len > existing_len {
21880                    continue;
21881                }
21882            }
21883
21884            result = Some(pair);
21885        }
21886
21887        result
21888    };
21889    let Some(pair) = pair else {
21890        return false;
21891    };
21892    pair.newline_only
21893        && buffer
21894            .chars_for_range(pair.open_range.end..range.start)
21895            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21896            .all(|c| c.is_whitespace() && c != '\n')
21897}
21898
21899fn update_uncommitted_diff_for_buffer(
21900    editor: Entity<Editor>,
21901    project: &Entity<Project>,
21902    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21903    buffer: Entity<MultiBuffer>,
21904    cx: &mut App,
21905) -> Task<()> {
21906    let mut tasks = Vec::new();
21907    project.update(cx, |project, cx| {
21908        for buffer in buffers {
21909            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21910                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21911            }
21912        }
21913    });
21914    cx.spawn(async move |cx| {
21915        let diffs = future::join_all(tasks).await;
21916        if editor
21917            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21918            .unwrap_or(false)
21919        {
21920            return;
21921        }
21922
21923        buffer
21924            .update(cx, |buffer, cx| {
21925                for diff in diffs.into_iter().flatten() {
21926                    buffer.add_diff(diff, cx);
21927                }
21928            })
21929            .ok();
21930    })
21931}
21932
21933fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21934    let tab_size = tab_size.get() as usize;
21935    let mut width = offset;
21936
21937    for ch in text.chars() {
21938        width += if ch == '\t' {
21939            tab_size - (width % tab_size)
21940        } else {
21941            1
21942        };
21943    }
21944
21945    width - offset
21946}
21947
21948#[cfg(test)]
21949mod tests {
21950    use super::*;
21951
21952    #[test]
21953    fn test_string_size_with_expanded_tabs() {
21954        let nz = |val| NonZeroU32::new(val).unwrap();
21955        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21956        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21957        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21958        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21959        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21960        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21961        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21962        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21963    }
21964}
21965
21966/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21967struct WordBreakingTokenizer<'a> {
21968    input: &'a str,
21969}
21970
21971impl<'a> WordBreakingTokenizer<'a> {
21972    fn new(input: &'a str) -> Self {
21973        Self { input }
21974    }
21975}
21976
21977fn is_char_ideographic(ch: char) -> bool {
21978    use unicode_script::Script::*;
21979    use unicode_script::UnicodeScript;
21980    matches!(ch.script(), Han | Tangut | Yi)
21981}
21982
21983fn is_grapheme_ideographic(text: &str) -> bool {
21984    text.chars().any(is_char_ideographic)
21985}
21986
21987fn is_grapheme_whitespace(text: &str) -> bool {
21988    text.chars().any(|x| x.is_whitespace())
21989}
21990
21991fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21992    text.chars()
21993        .next()
21994        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21995}
21996
21997#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21998enum WordBreakToken<'a> {
21999    Word { token: &'a str, grapheme_len: usize },
22000    InlineWhitespace { token: &'a str, grapheme_len: usize },
22001    Newline,
22002}
22003
22004impl<'a> Iterator for WordBreakingTokenizer<'a> {
22005    /// Yields a span, the count of graphemes in the token, and whether it was
22006    /// whitespace. Note that it also breaks at word boundaries.
22007    type Item = WordBreakToken<'a>;
22008
22009    fn next(&mut self) -> Option<Self::Item> {
22010        use unicode_segmentation::UnicodeSegmentation;
22011        if self.input.is_empty() {
22012            return None;
22013        }
22014
22015        let mut iter = self.input.graphemes(true).peekable();
22016        let mut offset = 0;
22017        let mut grapheme_len = 0;
22018        if let Some(first_grapheme) = iter.next() {
22019            let is_newline = first_grapheme == "\n";
22020            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22021            offset += first_grapheme.len();
22022            grapheme_len += 1;
22023            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22024                if let Some(grapheme) = iter.peek().copied()
22025                    && should_stay_with_preceding_ideograph(grapheme)
22026                {
22027                    offset += grapheme.len();
22028                    grapheme_len += 1;
22029                }
22030            } else {
22031                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22032                let mut next_word_bound = words.peek().copied();
22033                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22034                    next_word_bound = words.next();
22035                }
22036                while let Some(grapheme) = iter.peek().copied() {
22037                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22038                        break;
22039                    };
22040                    if is_grapheme_whitespace(grapheme) != is_whitespace
22041                        || (grapheme == "\n") != is_newline
22042                    {
22043                        break;
22044                    };
22045                    offset += grapheme.len();
22046                    grapheme_len += 1;
22047                    iter.next();
22048                }
22049            }
22050            let token = &self.input[..offset];
22051            self.input = &self.input[offset..];
22052            if token == "\n" {
22053                Some(WordBreakToken::Newline)
22054            } else if is_whitespace {
22055                Some(WordBreakToken::InlineWhitespace {
22056                    token,
22057                    grapheme_len,
22058                })
22059            } else {
22060                Some(WordBreakToken::Word {
22061                    token,
22062                    grapheme_len,
22063                })
22064            }
22065        } else {
22066            None
22067        }
22068    }
22069}
22070
22071#[test]
22072fn test_word_breaking_tokenizer() {
22073    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22074        ("", &[]),
22075        ("  ", &[whitespace("  ", 2)]),
22076        ("Ʒ", &[word("Ʒ", 1)]),
22077        ("Ǽ", &[word("Ǽ", 1)]),
22078        ("", &[word("", 1)]),
22079        ("⋑⋑", &[word("⋑⋑", 2)]),
22080        (
22081            "原理,进而",
22082            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22083        ),
22084        (
22085            "hello world",
22086            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22087        ),
22088        (
22089            "hello, world",
22090            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22091        ),
22092        (
22093            "  hello world",
22094            &[
22095                whitespace("  ", 2),
22096                word("hello", 5),
22097                whitespace(" ", 1),
22098                word("world", 5),
22099            ],
22100        ),
22101        (
22102            "这是什么 \n 钢笔",
22103            &[
22104                word("", 1),
22105                word("", 1),
22106                word("", 1),
22107                word("", 1),
22108                whitespace(" ", 1),
22109                newline(),
22110                whitespace(" ", 1),
22111                word("", 1),
22112                word("", 1),
22113            ],
22114        ),
22115        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22116    ];
22117
22118    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22119        WordBreakToken::Word {
22120            token,
22121            grapheme_len,
22122        }
22123    }
22124
22125    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22126        WordBreakToken::InlineWhitespace {
22127            token,
22128            grapheme_len,
22129        }
22130    }
22131
22132    fn newline() -> WordBreakToken<'static> {
22133        WordBreakToken::Newline
22134    }
22135
22136    for (input, result) in tests {
22137        assert_eq!(
22138            WordBreakingTokenizer::new(input)
22139                .collect::<Vec<_>>()
22140                .as_slice(),
22141            *result,
22142        );
22143    }
22144}
22145
22146fn wrap_with_prefix(
22147    first_line_prefix: String,
22148    subsequent_lines_prefix: String,
22149    unwrapped_text: String,
22150    wrap_column: usize,
22151    tab_size: NonZeroU32,
22152    preserve_existing_whitespace: bool,
22153) -> String {
22154    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22155    let subsequent_lines_prefix_len =
22156        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22157    let mut wrapped_text = String::new();
22158    let mut current_line = first_line_prefix;
22159    let mut is_first_line = true;
22160
22161    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22162    let mut current_line_len = first_line_prefix_len;
22163    let mut in_whitespace = false;
22164    for token in tokenizer {
22165        let have_preceding_whitespace = in_whitespace;
22166        match token {
22167            WordBreakToken::Word {
22168                token,
22169                grapheme_len,
22170            } => {
22171                in_whitespace = false;
22172                let current_prefix_len = if is_first_line {
22173                    first_line_prefix_len
22174                } else {
22175                    subsequent_lines_prefix_len
22176                };
22177                if current_line_len + grapheme_len > wrap_column
22178                    && current_line_len != current_prefix_len
22179                {
22180                    wrapped_text.push_str(current_line.trim_end());
22181                    wrapped_text.push('\n');
22182                    is_first_line = false;
22183                    current_line = subsequent_lines_prefix.clone();
22184                    current_line_len = subsequent_lines_prefix_len;
22185                }
22186                current_line.push_str(token);
22187                current_line_len += grapheme_len;
22188            }
22189            WordBreakToken::InlineWhitespace {
22190                mut token,
22191                mut grapheme_len,
22192            } => {
22193                in_whitespace = true;
22194                if have_preceding_whitespace && !preserve_existing_whitespace {
22195                    continue;
22196                }
22197                if !preserve_existing_whitespace {
22198                    token = " ";
22199                    grapheme_len = 1;
22200                }
22201                let current_prefix_len = if is_first_line {
22202                    first_line_prefix_len
22203                } else {
22204                    subsequent_lines_prefix_len
22205                };
22206                if current_line_len + grapheme_len > wrap_column {
22207                    wrapped_text.push_str(current_line.trim_end());
22208                    wrapped_text.push('\n');
22209                    is_first_line = false;
22210                    current_line = subsequent_lines_prefix.clone();
22211                    current_line_len = subsequent_lines_prefix_len;
22212                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22213                    current_line.push_str(token);
22214                    current_line_len += grapheme_len;
22215                }
22216            }
22217            WordBreakToken::Newline => {
22218                in_whitespace = true;
22219                let current_prefix_len = if is_first_line {
22220                    first_line_prefix_len
22221                } else {
22222                    subsequent_lines_prefix_len
22223                };
22224                if preserve_existing_whitespace {
22225                    wrapped_text.push_str(current_line.trim_end());
22226                    wrapped_text.push('\n');
22227                    is_first_line = false;
22228                    current_line = subsequent_lines_prefix.clone();
22229                    current_line_len = subsequent_lines_prefix_len;
22230                } else if have_preceding_whitespace {
22231                    continue;
22232                } else if current_line_len + 1 > wrap_column
22233                    && current_line_len != current_prefix_len
22234                {
22235                    wrapped_text.push_str(current_line.trim_end());
22236                    wrapped_text.push('\n');
22237                    is_first_line = false;
22238                    current_line = subsequent_lines_prefix.clone();
22239                    current_line_len = subsequent_lines_prefix_len;
22240                } else if current_line_len != current_prefix_len {
22241                    current_line.push(' ');
22242                    current_line_len += 1;
22243                }
22244            }
22245        }
22246    }
22247
22248    if !current_line.is_empty() {
22249        wrapped_text.push_str(&current_line);
22250    }
22251    wrapped_text
22252}
22253
22254#[test]
22255fn test_wrap_with_prefix() {
22256    assert_eq!(
22257        wrap_with_prefix(
22258            "# ".to_string(),
22259            "# ".to_string(),
22260            "abcdefg".to_string(),
22261            4,
22262            NonZeroU32::new(4).unwrap(),
22263            false,
22264        ),
22265        "# abcdefg"
22266    );
22267    assert_eq!(
22268        wrap_with_prefix(
22269            "".to_string(),
22270            "".to_string(),
22271            "\thello world".to_string(),
22272            8,
22273            NonZeroU32::new(4).unwrap(),
22274            false,
22275        ),
22276        "hello\nworld"
22277    );
22278    assert_eq!(
22279        wrap_with_prefix(
22280            "// ".to_string(),
22281            "// ".to_string(),
22282            "xx \nyy zz aa bb cc".to_string(),
22283            12,
22284            NonZeroU32::new(4).unwrap(),
22285            false,
22286        ),
22287        "// xx yy zz\n// aa bb cc"
22288    );
22289    assert_eq!(
22290        wrap_with_prefix(
22291            String::new(),
22292            String::new(),
22293            "这是什么 \n 钢笔".to_string(),
22294            3,
22295            NonZeroU32::new(4).unwrap(),
22296            false,
22297        ),
22298        "这是什\n么 钢\n"
22299    );
22300}
22301
22302pub trait CollaborationHub {
22303    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22304    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22305    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22306}
22307
22308impl CollaborationHub for Entity<Project> {
22309    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22310        self.read(cx).collaborators()
22311    }
22312
22313    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22314        self.read(cx).user_store().read(cx).participant_indices()
22315    }
22316
22317    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22318        let this = self.read(cx);
22319        let user_ids = this.collaborators().values().map(|c| c.user_id);
22320        this.user_store().read(cx).participant_names(user_ids, cx)
22321    }
22322}
22323
22324pub trait SemanticsProvider {
22325    fn hover(
22326        &self,
22327        buffer: &Entity<Buffer>,
22328        position: text::Anchor,
22329        cx: &mut App,
22330    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22331
22332    fn inline_values(
22333        &self,
22334        buffer_handle: Entity<Buffer>,
22335        range: Range<text::Anchor>,
22336        cx: &mut App,
22337    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22338
22339    fn inlay_hints(
22340        &self,
22341        buffer_handle: Entity<Buffer>,
22342        range: Range<text::Anchor>,
22343        cx: &mut App,
22344    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22345
22346    fn resolve_inlay_hint(
22347        &self,
22348        hint: InlayHint,
22349        buffer_handle: Entity<Buffer>,
22350        server_id: LanguageServerId,
22351        cx: &mut App,
22352    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22353
22354    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22355
22356    fn document_highlights(
22357        &self,
22358        buffer: &Entity<Buffer>,
22359        position: text::Anchor,
22360        cx: &mut App,
22361    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22362
22363    fn definitions(
22364        &self,
22365        buffer: &Entity<Buffer>,
22366        position: text::Anchor,
22367        kind: GotoDefinitionKind,
22368        cx: &mut App,
22369    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22370
22371    fn range_for_rename(
22372        &self,
22373        buffer: &Entity<Buffer>,
22374        position: text::Anchor,
22375        cx: &mut App,
22376    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22377
22378    fn perform_rename(
22379        &self,
22380        buffer: &Entity<Buffer>,
22381        position: text::Anchor,
22382        new_name: String,
22383        cx: &mut App,
22384    ) -> Option<Task<Result<ProjectTransaction>>>;
22385}
22386
22387pub trait CompletionProvider {
22388    fn completions(
22389        &self,
22390        excerpt_id: ExcerptId,
22391        buffer: &Entity<Buffer>,
22392        buffer_position: text::Anchor,
22393        trigger: CompletionContext,
22394        window: &mut Window,
22395        cx: &mut Context<Editor>,
22396    ) -> Task<Result<Vec<CompletionResponse>>>;
22397
22398    fn resolve_completions(
22399        &self,
22400        _buffer: Entity<Buffer>,
22401        _completion_indices: Vec<usize>,
22402        _completions: Rc<RefCell<Box<[Completion]>>>,
22403        _cx: &mut Context<Editor>,
22404    ) -> Task<Result<bool>> {
22405        Task::ready(Ok(false))
22406    }
22407
22408    fn apply_additional_edits_for_completion(
22409        &self,
22410        _buffer: Entity<Buffer>,
22411        _completions: Rc<RefCell<Box<[Completion]>>>,
22412        _completion_index: usize,
22413        _push_to_history: bool,
22414        _cx: &mut Context<Editor>,
22415    ) -> Task<Result<Option<language::Transaction>>> {
22416        Task::ready(Ok(None))
22417    }
22418
22419    fn is_completion_trigger(
22420        &self,
22421        buffer: &Entity<Buffer>,
22422        position: language::Anchor,
22423        text: &str,
22424        trigger_in_words: bool,
22425        menu_is_open: bool,
22426        cx: &mut Context<Editor>,
22427    ) -> bool;
22428
22429    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22430
22431    fn sort_completions(&self) -> bool {
22432        true
22433    }
22434
22435    fn filter_completions(&self) -> bool {
22436        true
22437    }
22438}
22439
22440pub trait CodeActionProvider {
22441    fn id(&self) -> Arc<str>;
22442
22443    fn code_actions(
22444        &self,
22445        buffer: &Entity<Buffer>,
22446        range: Range<text::Anchor>,
22447        window: &mut Window,
22448        cx: &mut App,
22449    ) -> Task<Result<Vec<CodeAction>>>;
22450
22451    fn apply_code_action(
22452        &self,
22453        buffer_handle: Entity<Buffer>,
22454        action: CodeAction,
22455        excerpt_id: ExcerptId,
22456        push_to_history: bool,
22457        window: &mut Window,
22458        cx: &mut App,
22459    ) -> Task<Result<ProjectTransaction>>;
22460}
22461
22462impl CodeActionProvider for Entity<Project> {
22463    fn id(&self) -> Arc<str> {
22464        "project".into()
22465    }
22466
22467    fn code_actions(
22468        &self,
22469        buffer: &Entity<Buffer>,
22470        range: Range<text::Anchor>,
22471        _window: &mut Window,
22472        cx: &mut App,
22473    ) -> Task<Result<Vec<CodeAction>>> {
22474        self.update(cx, |project, cx| {
22475            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22476            let code_actions = project.code_actions(buffer, range, None, cx);
22477            cx.background_spawn(async move {
22478                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22479                Ok(code_lens_actions
22480                    .context("code lens fetch")?
22481                    .into_iter()
22482                    .flatten()
22483                    .chain(
22484                        code_actions
22485                            .context("code action fetch")?
22486                            .into_iter()
22487                            .flatten(),
22488                    )
22489                    .collect())
22490            })
22491        })
22492    }
22493
22494    fn apply_code_action(
22495        &self,
22496        buffer_handle: Entity<Buffer>,
22497        action: CodeAction,
22498        _excerpt_id: ExcerptId,
22499        push_to_history: bool,
22500        _window: &mut Window,
22501        cx: &mut App,
22502    ) -> Task<Result<ProjectTransaction>> {
22503        self.update(cx, |project, cx| {
22504            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22505        })
22506    }
22507}
22508
22509fn snippet_completions(
22510    project: &Project,
22511    buffer: &Entity<Buffer>,
22512    buffer_position: text::Anchor,
22513    cx: &mut App,
22514) -> Task<Result<CompletionResponse>> {
22515    let languages = buffer.read(cx).languages_at(buffer_position);
22516    let snippet_store = project.snippets().read(cx);
22517
22518    let scopes: Vec<_> = languages
22519        .iter()
22520        .filter_map(|language| {
22521            let language_name = language.lsp_id();
22522            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22523
22524            if snippets.is_empty() {
22525                None
22526            } else {
22527                Some((language.default_scope(), snippets))
22528            }
22529        })
22530        .collect();
22531
22532    if scopes.is_empty() {
22533        return Task::ready(Ok(CompletionResponse {
22534            completions: vec![],
22535            display_options: CompletionDisplayOptions::default(),
22536            is_incomplete: false,
22537        }));
22538    }
22539
22540    let snapshot = buffer.read(cx).text_snapshot();
22541    let chars: String = snapshot
22542        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22543        .collect();
22544    let executor = cx.background_executor().clone();
22545
22546    cx.background_spawn(async move {
22547        let mut is_incomplete = false;
22548        let mut completions: Vec<Completion> = Vec::new();
22549        for (scope, snippets) in scopes.into_iter() {
22550            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22551            let mut last_word = chars
22552                .chars()
22553                .take_while(|c| classifier.is_word(*c))
22554                .collect::<String>();
22555            last_word = last_word.chars().rev().collect();
22556
22557            if last_word.is_empty() {
22558                return Ok(CompletionResponse {
22559                    completions: vec![],
22560                    display_options: CompletionDisplayOptions::default(),
22561                    is_incomplete: true,
22562                });
22563            }
22564
22565            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22566            let to_lsp = |point: &text::Anchor| {
22567                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22568                point_to_lsp(end)
22569            };
22570            let lsp_end = to_lsp(&buffer_position);
22571
22572            let candidates = snippets
22573                .iter()
22574                .enumerate()
22575                .flat_map(|(ix, snippet)| {
22576                    snippet
22577                        .prefix
22578                        .iter()
22579                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22580                })
22581                .collect::<Vec<StringMatchCandidate>>();
22582
22583            const MAX_RESULTS: usize = 100;
22584            let mut matches = fuzzy::match_strings(
22585                &candidates,
22586                &last_word,
22587                last_word.chars().any(|c| c.is_uppercase()),
22588                true,
22589                MAX_RESULTS,
22590                &Default::default(),
22591                executor.clone(),
22592            )
22593            .await;
22594
22595            if matches.len() >= MAX_RESULTS {
22596                is_incomplete = true;
22597            }
22598
22599            // Remove all candidates where the query's start does not match the start of any word in the candidate
22600            if let Some(query_start) = last_word.chars().next() {
22601                matches.retain(|string_match| {
22602                    split_words(&string_match.string).any(|word| {
22603                        // Check that the first codepoint of the word as lowercase matches the first
22604                        // codepoint of the query as lowercase
22605                        word.chars()
22606                            .flat_map(|codepoint| codepoint.to_lowercase())
22607                            .zip(query_start.to_lowercase())
22608                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22609                    })
22610                });
22611            }
22612
22613            let matched_strings = matches
22614                .into_iter()
22615                .map(|m| m.string)
22616                .collect::<HashSet<_>>();
22617
22618            completions.extend(snippets.iter().filter_map(|snippet| {
22619                let matching_prefix = snippet
22620                    .prefix
22621                    .iter()
22622                    .find(|prefix| matched_strings.contains(*prefix))?;
22623                let start = as_offset - last_word.len();
22624                let start = snapshot.anchor_before(start);
22625                let range = start..buffer_position;
22626                let lsp_start = to_lsp(&start);
22627                let lsp_range = lsp::Range {
22628                    start: lsp_start,
22629                    end: lsp_end,
22630                };
22631                Some(Completion {
22632                    replace_range: range,
22633                    new_text: snippet.body.clone(),
22634                    source: CompletionSource::Lsp {
22635                        insert_range: None,
22636                        server_id: LanguageServerId(usize::MAX),
22637                        resolved: true,
22638                        lsp_completion: Box::new(lsp::CompletionItem {
22639                            label: snippet.prefix.first().unwrap().clone(),
22640                            kind: Some(CompletionItemKind::SNIPPET),
22641                            label_details: snippet.description.as_ref().map(|description| {
22642                                lsp::CompletionItemLabelDetails {
22643                                    detail: Some(description.clone()),
22644                                    description: None,
22645                                }
22646                            }),
22647                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22648                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22649                                lsp::InsertReplaceEdit {
22650                                    new_text: snippet.body.clone(),
22651                                    insert: lsp_range,
22652                                    replace: lsp_range,
22653                                },
22654                            )),
22655                            filter_text: Some(snippet.body.clone()),
22656                            sort_text: Some(char::MAX.to_string()),
22657                            ..lsp::CompletionItem::default()
22658                        }),
22659                        lsp_defaults: None,
22660                    },
22661                    label: CodeLabel {
22662                        text: matching_prefix.clone(),
22663                        runs: Vec::new(),
22664                        filter_range: 0..matching_prefix.len(),
22665                    },
22666                    icon_path: None,
22667                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22668                        single_line: snippet.name.clone().into(),
22669                        plain_text: snippet
22670                            .description
22671                            .clone()
22672                            .map(|description| description.into()),
22673                    }),
22674                    insert_text_mode: None,
22675                    confirm: None,
22676                })
22677            }))
22678        }
22679
22680        Ok(CompletionResponse {
22681            completions,
22682            display_options: CompletionDisplayOptions::default(),
22683            is_incomplete,
22684        })
22685    })
22686}
22687
22688impl CompletionProvider for Entity<Project> {
22689    fn completions(
22690        &self,
22691        _excerpt_id: ExcerptId,
22692        buffer: &Entity<Buffer>,
22693        buffer_position: text::Anchor,
22694        options: CompletionContext,
22695        _window: &mut Window,
22696        cx: &mut Context<Editor>,
22697    ) -> Task<Result<Vec<CompletionResponse>>> {
22698        self.update(cx, |project, cx| {
22699            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22700            let project_completions = project.completions(buffer, buffer_position, options, cx);
22701            cx.background_spawn(async move {
22702                let mut responses = project_completions.await?;
22703                let snippets = snippets.await?;
22704                if !snippets.completions.is_empty() {
22705                    responses.push(snippets);
22706                }
22707                Ok(responses)
22708            })
22709        })
22710    }
22711
22712    fn resolve_completions(
22713        &self,
22714        buffer: Entity<Buffer>,
22715        completion_indices: Vec<usize>,
22716        completions: Rc<RefCell<Box<[Completion]>>>,
22717        cx: &mut Context<Editor>,
22718    ) -> Task<Result<bool>> {
22719        self.update(cx, |project, cx| {
22720            project.lsp_store().update(cx, |lsp_store, cx| {
22721                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22722            })
22723        })
22724    }
22725
22726    fn apply_additional_edits_for_completion(
22727        &self,
22728        buffer: Entity<Buffer>,
22729        completions: Rc<RefCell<Box<[Completion]>>>,
22730        completion_index: usize,
22731        push_to_history: bool,
22732        cx: &mut Context<Editor>,
22733    ) -> Task<Result<Option<language::Transaction>>> {
22734        self.update(cx, |project, cx| {
22735            project.lsp_store().update(cx, |lsp_store, cx| {
22736                lsp_store.apply_additional_edits_for_completion(
22737                    buffer,
22738                    completions,
22739                    completion_index,
22740                    push_to_history,
22741                    cx,
22742                )
22743            })
22744        })
22745    }
22746
22747    fn is_completion_trigger(
22748        &self,
22749        buffer: &Entity<Buffer>,
22750        position: language::Anchor,
22751        text: &str,
22752        trigger_in_words: bool,
22753        menu_is_open: bool,
22754        cx: &mut Context<Editor>,
22755    ) -> bool {
22756        let mut chars = text.chars();
22757        let char = if let Some(char) = chars.next() {
22758            char
22759        } else {
22760            return false;
22761        };
22762        if chars.next().is_some() {
22763            return false;
22764        }
22765
22766        let buffer = buffer.read(cx);
22767        let snapshot = buffer.snapshot();
22768        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22769            return false;
22770        }
22771        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22772        if trigger_in_words && classifier.is_word(char) {
22773            return true;
22774        }
22775
22776        buffer.completion_triggers().contains(text)
22777    }
22778}
22779
22780impl SemanticsProvider for Entity<Project> {
22781    fn hover(
22782        &self,
22783        buffer: &Entity<Buffer>,
22784        position: text::Anchor,
22785        cx: &mut App,
22786    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22787        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22788    }
22789
22790    fn document_highlights(
22791        &self,
22792        buffer: &Entity<Buffer>,
22793        position: text::Anchor,
22794        cx: &mut App,
22795    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22796        Some(self.update(cx, |project, cx| {
22797            project.document_highlights(buffer, position, cx)
22798        }))
22799    }
22800
22801    fn definitions(
22802        &self,
22803        buffer: &Entity<Buffer>,
22804        position: text::Anchor,
22805        kind: GotoDefinitionKind,
22806        cx: &mut App,
22807    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22808        Some(self.update(cx, |project, cx| match kind {
22809            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22810            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22811            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22812            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22813        }))
22814    }
22815
22816    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22817        self.update(cx, |project, cx| {
22818            if project
22819                .active_debug_session(cx)
22820                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22821            {
22822                return true;
22823            }
22824
22825            buffer.update(cx, |buffer, cx| {
22826                project.any_language_server_supports_inlay_hints(buffer, cx)
22827            })
22828        })
22829    }
22830
22831    fn inline_values(
22832        &self,
22833        buffer_handle: Entity<Buffer>,
22834        range: Range<text::Anchor>,
22835        cx: &mut App,
22836    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22837        self.update(cx, |project, cx| {
22838            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22839
22840            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22841        })
22842    }
22843
22844    fn inlay_hints(
22845        &self,
22846        buffer_handle: Entity<Buffer>,
22847        range: Range<text::Anchor>,
22848        cx: &mut App,
22849    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22850        Some(self.update(cx, |project, cx| {
22851            project.inlay_hints(buffer_handle, range, cx)
22852        }))
22853    }
22854
22855    fn resolve_inlay_hint(
22856        &self,
22857        hint: InlayHint,
22858        buffer_handle: Entity<Buffer>,
22859        server_id: LanguageServerId,
22860        cx: &mut App,
22861    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22862        Some(self.update(cx, |project, cx| {
22863            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22864        }))
22865    }
22866
22867    fn range_for_rename(
22868        &self,
22869        buffer: &Entity<Buffer>,
22870        position: text::Anchor,
22871        cx: &mut App,
22872    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22873        Some(self.update(cx, |project, cx| {
22874            let buffer = buffer.clone();
22875            let task = project.prepare_rename(buffer.clone(), position, cx);
22876            cx.spawn(async move |_, cx| {
22877                Ok(match task.await? {
22878                    PrepareRenameResponse::Success(range) => Some(range),
22879                    PrepareRenameResponse::InvalidPosition => None,
22880                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22881                        // Fallback on using TreeSitter info to determine identifier range
22882                        buffer.read_with(cx, |buffer, _| {
22883                            let snapshot = buffer.snapshot();
22884                            let (range, kind) = snapshot.surrounding_word(position, false);
22885                            if kind != Some(CharKind::Word) {
22886                                return None;
22887                            }
22888                            Some(
22889                                snapshot.anchor_before(range.start)
22890                                    ..snapshot.anchor_after(range.end),
22891                            )
22892                        })?
22893                    }
22894                })
22895            })
22896        }))
22897    }
22898
22899    fn perform_rename(
22900        &self,
22901        buffer: &Entity<Buffer>,
22902        position: text::Anchor,
22903        new_name: String,
22904        cx: &mut App,
22905    ) -> Option<Task<Result<ProjectTransaction>>> {
22906        Some(self.update(cx, |project, cx| {
22907            project.perform_rename(buffer.clone(), position, new_name, cx)
22908        }))
22909    }
22910}
22911
22912fn inlay_hint_settings(
22913    location: Anchor,
22914    snapshot: &MultiBufferSnapshot,
22915    cx: &mut Context<Editor>,
22916) -> InlayHintSettings {
22917    let file = snapshot.file_at(location);
22918    let language = snapshot.language_at(location).map(|l| l.name());
22919    language_settings(language, file, cx).inlay_hints
22920}
22921
22922fn consume_contiguous_rows(
22923    contiguous_row_selections: &mut Vec<Selection<Point>>,
22924    selection: &Selection<Point>,
22925    display_map: &DisplaySnapshot,
22926    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22927) -> (MultiBufferRow, MultiBufferRow) {
22928    contiguous_row_selections.push(selection.clone());
22929    let start_row = starting_row(selection, display_map);
22930    let mut end_row = ending_row(selection, display_map);
22931
22932    while let Some(next_selection) = selections.peek() {
22933        if next_selection.start.row <= end_row.0 {
22934            end_row = ending_row(next_selection, display_map);
22935            contiguous_row_selections.push(selections.next().unwrap().clone());
22936        } else {
22937            break;
22938        }
22939    }
22940    (start_row, end_row)
22941}
22942
22943fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22944    if selection.start.column > 0 {
22945        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22946    } else {
22947        MultiBufferRow(selection.start.row)
22948    }
22949}
22950
22951fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22952    if next_selection.end.column > 0 || next_selection.is_empty() {
22953        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22954    } else {
22955        MultiBufferRow(next_selection.end.row)
22956    }
22957}
22958
22959impl EditorSnapshot {
22960    pub fn remote_selections_in_range<'a>(
22961        &'a self,
22962        range: &'a Range<Anchor>,
22963        collaboration_hub: &dyn CollaborationHub,
22964        cx: &'a App,
22965    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22966        let participant_names = collaboration_hub.user_names(cx);
22967        let participant_indices = collaboration_hub.user_participant_indices(cx);
22968        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22969        let collaborators_by_replica_id = collaborators_by_peer_id
22970            .values()
22971            .map(|collaborator| (collaborator.replica_id, collaborator))
22972            .collect::<HashMap<_, _>>();
22973        self.buffer_snapshot
22974            .selections_in_range(range, false)
22975            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22976                if replica_id == AGENT_REPLICA_ID {
22977                    Some(RemoteSelection {
22978                        replica_id,
22979                        selection,
22980                        cursor_shape,
22981                        line_mode,
22982                        collaborator_id: CollaboratorId::Agent,
22983                        user_name: Some("Agent".into()),
22984                        color: cx.theme().players().agent(),
22985                    })
22986                } else {
22987                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22988                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22989                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22990                    Some(RemoteSelection {
22991                        replica_id,
22992                        selection,
22993                        cursor_shape,
22994                        line_mode,
22995                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22996                        user_name,
22997                        color: if let Some(index) = participant_index {
22998                            cx.theme().players().color_for_participant(index.0)
22999                        } else {
23000                            cx.theme().players().absent()
23001                        },
23002                    })
23003                }
23004            })
23005    }
23006
23007    pub fn hunks_for_ranges(
23008        &self,
23009        ranges: impl IntoIterator<Item = Range<Point>>,
23010    ) -> Vec<MultiBufferDiffHunk> {
23011        let mut hunks = Vec::new();
23012        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23013            HashMap::default();
23014        for query_range in ranges {
23015            let query_rows =
23016                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23017            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23018                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23019            ) {
23020                // Include deleted hunks that are adjacent to the query range, because
23021                // otherwise they would be missed.
23022                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23023                if hunk.status().is_deleted() {
23024                    intersects_range |= hunk.row_range.start == query_rows.end;
23025                    intersects_range |= hunk.row_range.end == query_rows.start;
23026                }
23027                if intersects_range {
23028                    if !processed_buffer_rows
23029                        .entry(hunk.buffer_id)
23030                        .or_default()
23031                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23032                    {
23033                        continue;
23034                    }
23035                    hunks.push(hunk);
23036                }
23037            }
23038        }
23039
23040        hunks
23041    }
23042
23043    fn display_diff_hunks_for_rows<'a>(
23044        &'a self,
23045        display_rows: Range<DisplayRow>,
23046        folded_buffers: &'a HashSet<BufferId>,
23047    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23048        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23049        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23050
23051        self.buffer_snapshot
23052            .diff_hunks_in_range(buffer_start..buffer_end)
23053            .filter_map(|hunk| {
23054                if folded_buffers.contains(&hunk.buffer_id) {
23055                    return None;
23056                }
23057
23058                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23059                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23060
23061                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23062                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23063
23064                let display_hunk = if hunk_display_start.column() != 0 {
23065                    DisplayDiffHunk::Folded {
23066                        display_row: hunk_display_start.row(),
23067                    }
23068                } else {
23069                    let mut end_row = hunk_display_end.row();
23070                    if hunk_display_end.column() > 0 {
23071                        end_row.0 += 1;
23072                    }
23073                    let is_created_file = hunk.is_created_file();
23074                    DisplayDiffHunk::Unfolded {
23075                        status: hunk.status(),
23076                        diff_base_byte_range: hunk.diff_base_byte_range,
23077                        display_row_range: hunk_display_start.row()..end_row,
23078                        multi_buffer_range: Anchor::range_in_buffer(
23079                            hunk.excerpt_id,
23080                            hunk.buffer_id,
23081                            hunk.buffer_range,
23082                        ),
23083                        is_created_file,
23084                    }
23085                };
23086
23087                Some(display_hunk)
23088            })
23089    }
23090
23091    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23092        self.display_snapshot.buffer_snapshot.language_at(position)
23093    }
23094
23095    pub fn is_focused(&self) -> bool {
23096        self.is_focused
23097    }
23098
23099    pub fn placeholder_text(&self) -> Option<String> {
23100        self.placeholder_display_snapshot
23101            .as_ref()
23102            .map(|display_map| display_map.text())
23103    }
23104
23105    pub fn scroll_position(&self) -> gpui::Point<f32> {
23106        self.scroll_anchor.scroll_position(&self.display_snapshot)
23107    }
23108
23109    fn gutter_dimensions(
23110        &self,
23111        font_id: FontId,
23112        font_size: Pixels,
23113        max_line_number_width: Pixels,
23114        cx: &App,
23115    ) -> Option<GutterDimensions> {
23116        if !self.show_gutter {
23117            return None;
23118        }
23119
23120        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23121        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23122
23123        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23124            matches!(
23125                ProjectSettings::get_global(cx).git.git_gutter,
23126                GitGutterSetting::TrackedFiles
23127            )
23128        });
23129        let gutter_settings = EditorSettings::get_global(cx).gutter;
23130        let show_line_numbers = self
23131            .show_line_numbers
23132            .unwrap_or(gutter_settings.line_numbers);
23133        let line_gutter_width = if show_line_numbers {
23134            // Avoid flicker-like gutter resizes when the line number gains another digit by
23135            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23136            let min_width_for_number_on_gutter =
23137                ch_advance * gutter_settings.min_line_number_digits as f32;
23138            max_line_number_width.max(min_width_for_number_on_gutter)
23139        } else {
23140            0.0.into()
23141        };
23142
23143        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23144        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23145
23146        let git_blame_entries_width =
23147            self.git_blame_gutter_max_author_length
23148                .map(|max_author_length| {
23149                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23150                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23151
23152                    /// The number of characters to dedicate to gaps and margins.
23153                    const SPACING_WIDTH: usize = 4;
23154
23155                    let max_char_count = max_author_length.min(renderer.max_author_length())
23156                        + ::git::SHORT_SHA_LENGTH
23157                        + MAX_RELATIVE_TIMESTAMP.len()
23158                        + SPACING_WIDTH;
23159
23160                    ch_advance * max_char_count
23161                });
23162
23163        let is_singleton = self.buffer_snapshot.is_singleton();
23164
23165        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23166        left_padding += if !is_singleton {
23167            ch_width * 4.0
23168        } else if show_runnables || show_breakpoints {
23169            ch_width * 3.0
23170        } else if show_git_gutter && show_line_numbers {
23171            ch_width * 2.0
23172        } else if show_git_gutter || show_line_numbers {
23173            ch_width
23174        } else {
23175            px(0.)
23176        };
23177
23178        let shows_folds = is_singleton && gutter_settings.folds;
23179
23180        let right_padding = if shows_folds && show_line_numbers {
23181            ch_width * 4.0
23182        } else if shows_folds || (!is_singleton && show_line_numbers) {
23183            ch_width * 3.0
23184        } else if show_line_numbers {
23185            ch_width
23186        } else {
23187            px(0.)
23188        };
23189
23190        Some(GutterDimensions {
23191            left_padding,
23192            right_padding,
23193            width: line_gutter_width + left_padding + right_padding,
23194            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23195            git_blame_entries_width,
23196        })
23197    }
23198
23199    pub fn render_crease_toggle(
23200        &self,
23201        buffer_row: MultiBufferRow,
23202        row_contains_cursor: bool,
23203        editor: Entity<Editor>,
23204        window: &mut Window,
23205        cx: &mut App,
23206    ) -> Option<AnyElement> {
23207        let folded = self.is_line_folded(buffer_row);
23208        let mut is_foldable = false;
23209
23210        if let Some(crease) = self
23211            .crease_snapshot
23212            .query_row(buffer_row, &self.buffer_snapshot)
23213        {
23214            is_foldable = true;
23215            match crease {
23216                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23217                    if let Some(render_toggle) = render_toggle {
23218                        let toggle_callback =
23219                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23220                                if folded {
23221                                    editor.update(cx, |editor, cx| {
23222                                        editor.fold_at(buffer_row, window, cx)
23223                                    });
23224                                } else {
23225                                    editor.update(cx, |editor, cx| {
23226                                        editor.unfold_at(buffer_row, window, cx)
23227                                    });
23228                                }
23229                            });
23230                        return Some((render_toggle)(
23231                            buffer_row,
23232                            folded,
23233                            toggle_callback,
23234                            window,
23235                            cx,
23236                        ));
23237                    }
23238                }
23239            }
23240        }
23241
23242        is_foldable |= self.starts_indent(buffer_row);
23243
23244        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23245            Some(
23246                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23247                    .toggle_state(folded)
23248                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23249                        if folded {
23250                            this.unfold_at(buffer_row, window, cx);
23251                        } else {
23252                            this.fold_at(buffer_row, window, cx);
23253                        }
23254                    }))
23255                    .into_any_element(),
23256            )
23257        } else {
23258            None
23259        }
23260    }
23261
23262    pub fn render_crease_trailer(
23263        &self,
23264        buffer_row: MultiBufferRow,
23265        window: &mut Window,
23266        cx: &mut App,
23267    ) -> Option<AnyElement> {
23268        let folded = self.is_line_folded(buffer_row);
23269        if let Crease::Inline { render_trailer, .. } = self
23270            .crease_snapshot
23271            .query_row(buffer_row, &self.buffer_snapshot)?
23272        {
23273            let render_trailer = render_trailer.as_ref()?;
23274            Some(render_trailer(buffer_row, folded, window, cx))
23275        } else {
23276            None
23277        }
23278    }
23279}
23280
23281impl Deref for EditorSnapshot {
23282    type Target = DisplaySnapshot;
23283
23284    fn deref(&self) -> &Self::Target {
23285        &self.display_snapshot
23286    }
23287}
23288
23289#[derive(Clone, Debug, PartialEq, Eq)]
23290pub enum EditorEvent {
23291    InputIgnored {
23292        text: Arc<str>,
23293    },
23294    InputHandled {
23295        utf16_range_to_replace: Option<Range<isize>>,
23296        text: Arc<str>,
23297    },
23298    ExcerptsAdded {
23299        buffer: Entity<Buffer>,
23300        predecessor: ExcerptId,
23301        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23302    },
23303    ExcerptsRemoved {
23304        ids: Vec<ExcerptId>,
23305        removed_buffer_ids: Vec<BufferId>,
23306    },
23307    BufferFoldToggled {
23308        ids: Vec<ExcerptId>,
23309        folded: bool,
23310    },
23311    ExcerptsEdited {
23312        ids: Vec<ExcerptId>,
23313    },
23314    ExcerptsExpanded {
23315        ids: Vec<ExcerptId>,
23316    },
23317    BufferEdited,
23318    Edited {
23319        transaction_id: clock::Lamport,
23320    },
23321    Reparsed(BufferId),
23322    Focused,
23323    FocusedIn,
23324    Blurred,
23325    DirtyChanged,
23326    Saved,
23327    TitleChanged,
23328    SelectionsChanged {
23329        local: bool,
23330    },
23331    ScrollPositionChanged {
23332        local: bool,
23333        autoscroll: bool,
23334    },
23335    TransactionUndone {
23336        transaction_id: clock::Lamport,
23337    },
23338    TransactionBegun {
23339        transaction_id: clock::Lamport,
23340    },
23341    CursorShapeChanged,
23342    BreadcrumbsChanged,
23343    PushedToNavHistory {
23344        anchor: Anchor,
23345        is_deactivate: bool,
23346    },
23347}
23348
23349impl EventEmitter<EditorEvent> for Editor {}
23350
23351impl Focusable for Editor {
23352    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23353        self.focus_handle.clone()
23354    }
23355}
23356
23357impl Render for Editor {
23358    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23359        let settings = ThemeSettings::get_global(cx);
23360
23361        let mut text_style = match self.mode {
23362            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23363                color: cx.theme().colors().editor_foreground,
23364                font_family: settings.ui_font.family.clone(),
23365                font_features: settings.ui_font.features.clone(),
23366                font_fallbacks: settings.ui_font.fallbacks.clone(),
23367                font_size: rems(0.875).into(),
23368                font_weight: settings.ui_font.weight,
23369                line_height: relative(settings.buffer_line_height.value()),
23370                ..Default::default()
23371            },
23372            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23373                color: cx.theme().colors().editor_foreground,
23374                font_family: settings.buffer_font.family.clone(),
23375                font_features: settings.buffer_font.features.clone(),
23376                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23377                font_size: settings.buffer_font_size(cx).into(),
23378                font_weight: settings.buffer_font.weight,
23379                line_height: relative(settings.buffer_line_height.value()),
23380                ..Default::default()
23381            },
23382        };
23383        if let Some(text_style_refinement) = &self.text_style_refinement {
23384            text_style.refine(text_style_refinement)
23385        }
23386
23387        let background = match self.mode {
23388            EditorMode::SingleLine => cx.theme().system().transparent,
23389            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23390            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23391            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23392        };
23393
23394        EditorElement::new(
23395            &cx.entity(),
23396            EditorStyle {
23397                background,
23398                border: cx.theme().colors().border,
23399                local_player: cx.theme().players().local(),
23400                text: text_style,
23401                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23402                syntax: cx.theme().syntax().clone(),
23403                status: cx.theme().status().clone(),
23404                inlay_hints_style: make_inlay_hints_style(cx),
23405                edit_prediction_styles: make_suggestion_styles(cx),
23406                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23407                show_underlines: self.diagnostics_enabled(),
23408            },
23409        )
23410    }
23411}
23412
23413impl EntityInputHandler for Editor {
23414    fn text_for_range(
23415        &mut self,
23416        range_utf16: Range<usize>,
23417        adjusted_range: &mut Option<Range<usize>>,
23418        _: &mut Window,
23419        cx: &mut Context<Self>,
23420    ) -> Option<String> {
23421        let snapshot = self.buffer.read(cx).read(cx);
23422        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23423        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23424        if (start.0..end.0) != range_utf16 {
23425            adjusted_range.replace(start.0..end.0);
23426        }
23427        Some(snapshot.text_for_range(start..end).collect())
23428    }
23429
23430    fn selected_text_range(
23431        &mut self,
23432        ignore_disabled_input: bool,
23433        _: &mut Window,
23434        cx: &mut Context<Self>,
23435    ) -> Option<UTF16Selection> {
23436        // Prevent the IME menu from appearing when holding down an alphabetic key
23437        // while input is disabled.
23438        if !ignore_disabled_input && !self.input_enabled {
23439            return None;
23440        }
23441
23442        let selection = self.selections.newest::<OffsetUtf16>(cx);
23443        let range = selection.range();
23444
23445        Some(UTF16Selection {
23446            range: range.start.0..range.end.0,
23447            reversed: selection.reversed,
23448        })
23449    }
23450
23451    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23452        let snapshot = self.buffer.read(cx).read(cx);
23453        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23454        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23455    }
23456
23457    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23458        self.clear_highlights::<InputComposition>(cx);
23459        self.ime_transaction.take();
23460    }
23461
23462    fn replace_text_in_range(
23463        &mut self,
23464        range_utf16: Option<Range<usize>>,
23465        text: &str,
23466        window: &mut Window,
23467        cx: &mut Context<Self>,
23468    ) {
23469        if !self.input_enabled {
23470            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23471            return;
23472        }
23473
23474        self.transact(window, cx, |this, window, cx| {
23475            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23476                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23477                Some(this.selection_replacement_ranges(range_utf16, cx))
23478            } else {
23479                this.marked_text_ranges(cx)
23480            };
23481
23482            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23483                let newest_selection_id = this.selections.newest_anchor().id;
23484                this.selections
23485                    .all::<OffsetUtf16>(cx)
23486                    .iter()
23487                    .zip(ranges_to_replace.iter())
23488                    .find_map(|(selection, range)| {
23489                        if selection.id == newest_selection_id {
23490                            Some(
23491                                (range.start.0 as isize - selection.head().0 as isize)
23492                                    ..(range.end.0 as isize - selection.head().0 as isize),
23493                            )
23494                        } else {
23495                            None
23496                        }
23497                    })
23498            });
23499
23500            cx.emit(EditorEvent::InputHandled {
23501                utf16_range_to_replace: range_to_replace,
23502                text: text.into(),
23503            });
23504
23505            if let Some(new_selected_ranges) = new_selected_ranges {
23506                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23507                    selections.select_ranges(new_selected_ranges)
23508                });
23509                this.backspace(&Default::default(), window, cx);
23510            }
23511
23512            this.handle_input(text, window, cx);
23513        });
23514
23515        if let Some(transaction) = self.ime_transaction {
23516            self.buffer.update(cx, |buffer, cx| {
23517                buffer.group_until_transaction(transaction, cx);
23518            });
23519        }
23520
23521        self.unmark_text(window, cx);
23522    }
23523
23524    fn replace_and_mark_text_in_range(
23525        &mut self,
23526        range_utf16: Option<Range<usize>>,
23527        text: &str,
23528        new_selected_range_utf16: Option<Range<usize>>,
23529        window: &mut Window,
23530        cx: &mut Context<Self>,
23531    ) {
23532        if !self.input_enabled {
23533            return;
23534        }
23535
23536        let transaction = self.transact(window, cx, |this, window, cx| {
23537            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23538                let snapshot = this.buffer.read(cx).read(cx);
23539                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23540                    for marked_range in &mut marked_ranges {
23541                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23542                        marked_range.start.0 += relative_range_utf16.start;
23543                        marked_range.start =
23544                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23545                        marked_range.end =
23546                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23547                    }
23548                }
23549                Some(marked_ranges)
23550            } else if let Some(range_utf16) = range_utf16 {
23551                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23552                Some(this.selection_replacement_ranges(range_utf16, cx))
23553            } else {
23554                None
23555            };
23556
23557            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23558                let newest_selection_id = this.selections.newest_anchor().id;
23559                this.selections
23560                    .all::<OffsetUtf16>(cx)
23561                    .iter()
23562                    .zip(ranges_to_replace.iter())
23563                    .find_map(|(selection, range)| {
23564                        if selection.id == newest_selection_id {
23565                            Some(
23566                                (range.start.0 as isize - selection.head().0 as isize)
23567                                    ..(range.end.0 as isize - selection.head().0 as isize),
23568                            )
23569                        } else {
23570                            None
23571                        }
23572                    })
23573            });
23574
23575            cx.emit(EditorEvent::InputHandled {
23576                utf16_range_to_replace: range_to_replace,
23577                text: text.into(),
23578            });
23579
23580            if let Some(ranges) = ranges_to_replace {
23581                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23582                    s.select_ranges(ranges)
23583                });
23584            }
23585
23586            let marked_ranges = {
23587                let snapshot = this.buffer.read(cx).read(cx);
23588                this.selections
23589                    .disjoint_anchors_arc()
23590                    .iter()
23591                    .map(|selection| {
23592                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23593                    })
23594                    .collect::<Vec<_>>()
23595            };
23596
23597            if text.is_empty() {
23598                this.unmark_text(window, cx);
23599            } else {
23600                this.highlight_text::<InputComposition>(
23601                    marked_ranges.clone(),
23602                    HighlightStyle {
23603                        underline: Some(UnderlineStyle {
23604                            thickness: px(1.),
23605                            color: None,
23606                            wavy: false,
23607                        }),
23608                        ..Default::default()
23609                    },
23610                    cx,
23611                );
23612            }
23613
23614            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23615            let use_autoclose = this.use_autoclose;
23616            let use_auto_surround = this.use_auto_surround;
23617            this.set_use_autoclose(false);
23618            this.set_use_auto_surround(false);
23619            this.handle_input(text, window, cx);
23620            this.set_use_autoclose(use_autoclose);
23621            this.set_use_auto_surround(use_auto_surround);
23622
23623            if let Some(new_selected_range) = new_selected_range_utf16 {
23624                let snapshot = this.buffer.read(cx).read(cx);
23625                let new_selected_ranges = marked_ranges
23626                    .into_iter()
23627                    .map(|marked_range| {
23628                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23629                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23630                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23631                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23632                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23633                    })
23634                    .collect::<Vec<_>>();
23635
23636                drop(snapshot);
23637                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23638                    selections.select_ranges(new_selected_ranges)
23639                });
23640            }
23641        });
23642
23643        self.ime_transaction = self.ime_transaction.or(transaction);
23644        if let Some(transaction) = self.ime_transaction {
23645            self.buffer.update(cx, |buffer, cx| {
23646                buffer.group_until_transaction(transaction, cx);
23647            });
23648        }
23649
23650        if self.text_highlights::<InputComposition>(cx).is_none() {
23651            self.ime_transaction.take();
23652        }
23653    }
23654
23655    fn bounds_for_range(
23656        &mut self,
23657        range_utf16: Range<usize>,
23658        element_bounds: gpui::Bounds<Pixels>,
23659        window: &mut Window,
23660        cx: &mut Context<Self>,
23661    ) -> Option<gpui::Bounds<Pixels>> {
23662        let text_layout_details = self.text_layout_details(window);
23663        let CharacterDimensions {
23664            em_width,
23665            em_advance,
23666            line_height,
23667        } = self.character_dimensions(window);
23668
23669        let snapshot = self.snapshot(window, cx);
23670        let scroll_position = snapshot.scroll_position();
23671        let scroll_left = scroll_position.x * em_advance;
23672
23673        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23674        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23675            + self.gutter_dimensions.full_width();
23676        let y = line_height * (start.row().as_f32() - scroll_position.y);
23677
23678        Some(Bounds {
23679            origin: element_bounds.origin + point(x, y),
23680            size: size(em_width, line_height),
23681        })
23682    }
23683
23684    fn character_index_for_point(
23685        &mut self,
23686        point: gpui::Point<Pixels>,
23687        _window: &mut Window,
23688        _cx: &mut Context<Self>,
23689    ) -> Option<usize> {
23690        let position_map = self.last_position_map.as_ref()?;
23691        if !position_map.text_hitbox.contains(&point) {
23692            return None;
23693        }
23694        let display_point = position_map.point_for_position(point).previous_valid;
23695        let anchor = position_map
23696            .snapshot
23697            .display_point_to_anchor(display_point, Bias::Left);
23698        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23699        Some(utf16_offset.0)
23700    }
23701}
23702
23703trait SelectionExt {
23704    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23705    fn spanned_rows(
23706        &self,
23707        include_end_if_at_line_start: bool,
23708        map: &DisplaySnapshot,
23709    ) -> Range<MultiBufferRow>;
23710}
23711
23712impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23713    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23714        let start = self
23715            .start
23716            .to_point(&map.buffer_snapshot)
23717            .to_display_point(map);
23718        let end = self
23719            .end
23720            .to_point(&map.buffer_snapshot)
23721            .to_display_point(map);
23722        if self.reversed {
23723            end..start
23724        } else {
23725            start..end
23726        }
23727    }
23728
23729    fn spanned_rows(
23730        &self,
23731        include_end_if_at_line_start: bool,
23732        map: &DisplaySnapshot,
23733    ) -> Range<MultiBufferRow> {
23734        let start = self.start.to_point(&map.buffer_snapshot);
23735        let mut end = self.end.to_point(&map.buffer_snapshot);
23736        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23737            end.row -= 1;
23738        }
23739
23740        let buffer_start = map.prev_line_boundary(start).0;
23741        let buffer_end = map.next_line_boundary(end).0;
23742        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23743    }
23744}
23745
23746impl<T: InvalidationRegion> InvalidationStack<T> {
23747    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23748    where
23749        S: Clone + ToOffset,
23750    {
23751        while let Some(region) = self.last() {
23752            let all_selections_inside_invalidation_ranges =
23753                if selections.len() == region.ranges().len() {
23754                    selections
23755                        .iter()
23756                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23757                        .all(|(selection, invalidation_range)| {
23758                            let head = selection.head().to_offset(buffer);
23759                            invalidation_range.start <= head && invalidation_range.end >= head
23760                        })
23761                } else {
23762                    false
23763                };
23764
23765            if all_selections_inside_invalidation_ranges {
23766                break;
23767            } else {
23768                self.pop();
23769            }
23770        }
23771    }
23772}
23773
23774impl<T> Default for InvalidationStack<T> {
23775    fn default() -> Self {
23776        Self(Default::default())
23777    }
23778}
23779
23780impl<T> Deref for InvalidationStack<T> {
23781    type Target = Vec<T>;
23782
23783    fn deref(&self) -> &Self::Target {
23784        &self.0
23785    }
23786}
23787
23788impl<T> DerefMut for InvalidationStack<T> {
23789    fn deref_mut(&mut self) -> &mut Self::Target {
23790        &mut self.0
23791    }
23792}
23793
23794impl InvalidationRegion for SnippetState {
23795    fn ranges(&self) -> &[Range<Anchor>] {
23796        &self.ranges[self.active_index]
23797    }
23798}
23799
23800fn edit_prediction_edit_text(
23801    current_snapshot: &BufferSnapshot,
23802    edits: &[(Range<Anchor>, String)],
23803    edit_preview: &EditPreview,
23804    include_deletions: bool,
23805    cx: &App,
23806) -> HighlightedText {
23807    let edits = edits
23808        .iter()
23809        .map(|(anchor, text)| {
23810            (
23811                anchor.start.text_anchor..anchor.end.text_anchor,
23812                text.clone(),
23813            )
23814        })
23815        .collect::<Vec<_>>();
23816
23817    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23818}
23819
23820fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23821    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23822    // Just show the raw edit text with basic styling
23823    let mut text = String::new();
23824    let mut highlights = Vec::new();
23825
23826    let insertion_highlight_style = HighlightStyle {
23827        color: Some(cx.theme().colors().text),
23828        ..Default::default()
23829    };
23830
23831    for (_, edit_text) in edits {
23832        let start_offset = text.len();
23833        text.push_str(edit_text);
23834        let end_offset = text.len();
23835
23836        if start_offset < end_offset {
23837            highlights.push((start_offset..end_offset, insertion_highlight_style));
23838        }
23839    }
23840
23841    HighlightedText {
23842        text: text.into(),
23843        highlights,
23844    }
23845}
23846
23847pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23848    match severity {
23849        lsp::DiagnosticSeverity::ERROR => colors.error,
23850        lsp::DiagnosticSeverity::WARNING => colors.warning,
23851        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23852        lsp::DiagnosticSeverity::HINT => colors.info,
23853        _ => colors.ignored,
23854    }
23855}
23856
23857pub fn styled_runs_for_code_label<'a>(
23858    label: &'a CodeLabel,
23859    syntax_theme: &'a theme::SyntaxTheme,
23860) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23861    let fade_out = HighlightStyle {
23862        fade_out: Some(0.35),
23863        ..Default::default()
23864    };
23865
23866    let mut prev_end = label.filter_range.end;
23867    label
23868        .runs
23869        .iter()
23870        .enumerate()
23871        .flat_map(move |(ix, (range, highlight_id))| {
23872            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23873                style
23874            } else {
23875                return Default::default();
23876            };
23877            let muted_style = style.highlight(fade_out);
23878
23879            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23880            if range.start >= label.filter_range.end {
23881                if range.start > prev_end {
23882                    runs.push((prev_end..range.start, fade_out));
23883                }
23884                runs.push((range.clone(), muted_style));
23885            } else if range.end <= label.filter_range.end {
23886                runs.push((range.clone(), style));
23887            } else {
23888                runs.push((range.start..label.filter_range.end, style));
23889                runs.push((label.filter_range.end..range.end, muted_style));
23890            }
23891            prev_end = cmp::max(prev_end, range.end);
23892
23893            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23894                runs.push((prev_end..label.text.len(), fade_out));
23895            }
23896
23897            runs
23898        })
23899}
23900
23901pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23902    let mut prev_index = 0;
23903    let mut prev_codepoint: Option<char> = None;
23904    text.char_indices()
23905        .chain([(text.len(), '\0')])
23906        .filter_map(move |(index, codepoint)| {
23907            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23908            let is_boundary = index == text.len()
23909                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23910                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23911            if is_boundary {
23912                let chunk = &text[prev_index..index];
23913                prev_index = index;
23914                Some(chunk)
23915            } else {
23916                None
23917            }
23918        })
23919}
23920
23921pub trait RangeToAnchorExt: Sized {
23922    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23923
23924    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23925        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23926        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23927    }
23928}
23929
23930impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23931    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23932        let start_offset = self.start.to_offset(snapshot);
23933        let end_offset = self.end.to_offset(snapshot);
23934        if start_offset == end_offset {
23935            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23936        } else {
23937            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23938        }
23939    }
23940}
23941
23942pub trait RowExt {
23943    fn as_f32(&self) -> f32;
23944
23945    fn next_row(&self) -> Self;
23946
23947    fn previous_row(&self) -> Self;
23948
23949    fn minus(&self, other: Self) -> u32;
23950}
23951
23952impl RowExt for DisplayRow {
23953    fn as_f32(&self) -> f32 {
23954        self.0 as f32
23955    }
23956
23957    fn next_row(&self) -> Self {
23958        Self(self.0 + 1)
23959    }
23960
23961    fn previous_row(&self) -> Self {
23962        Self(self.0.saturating_sub(1))
23963    }
23964
23965    fn minus(&self, other: Self) -> u32 {
23966        self.0 - other.0
23967    }
23968}
23969
23970impl RowExt for MultiBufferRow {
23971    fn as_f32(&self) -> f32 {
23972        self.0 as f32
23973    }
23974
23975    fn next_row(&self) -> Self {
23976        Self(self.0 + 1)
23977    }
23978
23979    fn previous_row(&self) -> Self {
23980        Self(self.0.saturating_sub(1))
23981    }
23982
23983    fn minus(&self, other: Self) -> u32 {
23984        self.0 - other.0
23985    }
23986}
23987
23988trait RowRangeExt {
23989    type Row;
23990
23991    fn len(&self) -> usize;
23992
23993    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23994}
23995
23996impl RowRangeExt for Range<MultiBufferRow> {
23997    type Row = MultiBufferRow;
23998
23999    fn len(&self) -> usize {
24000        (self.end.0 - self.start.0) as usize
24001    }
24002
24003    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24004        (self.start.0..self.end.0).map(MultiBufferRow)
24005    }
24006}
24007
24008impl RowRangeExt for Range<DisplayRow> {
24009    type Row = DisplayRow;
24010
24011    fn len(&self) -> usize {
24012        (self.end.0 - self.start.0) as usize
24013    }
24014
24015    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24016        (self.start.0..self.end.0).map(DisplayRow)
24017    }
24018}
24019
24020/// If select range has more than one line, we
24021/// just point the cursor to range.start.
24022fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24023    if range.start.row == range.end.row {
24024        range
24025    } else {
24026        range.start..range.start
24027    }
24028}
24029pub struct KillRing(ClipboardItem);
24030impl Global for KillRing {}
24031
24032const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24033
24034enum BreakpointPromptEditAction {
24035    Log,
24036    Condition,
24037    HitCondition,
24038}
24039
24040struct BreakpointPromptEditor {
24041    pub(crate) prompt: Entity<Editor>,
24042    editor: WeakEntity<Editor>,
24043    breakpoint_anchor: Anchor,
24044    breakpoint: Breakpoint,
24045    edit_action: BreakpointPromptEditAction,
24046    block_ids: HashSet<CustomBlockId>,
24047    editor_margins: Arc<Mutex<EditorMargins>>,
24048    _subscriptions: Vec<Subscription>,
24049}
24050
24051impl BreakpointPromptEditor {
24052    const MAX_LINES: u8 = 4;
24053
24054    fn new(
24055        editor: WeakEntity<Editor>,
24056        breakpoint_anchor: Anchor,
24057        breakpoint: Breakpoint,
24058        edit_action: BreakpointPromptEditAction,
24059        window: &mut Window,
24060        cx: &mut Context<Self>,
24061    ) -> Self {
24062        let base_text = match edit_action {
24063            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24064            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24065            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24066        }
24067        .map(|msg| msg.to_string())
24068        .unwrap_or_default();
24069
24070        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24071        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24072
24073        let prompt = cx.new(|cx| {
24074            let mut prompt = Editor::new(
24075                EditorMode::AutoHeight {
24076                    min_lines: 1,
24077                    max_lines: Some(Self::MAX_LINES as usize),
24078                },
24079                buffer,
24080                None,
24081                window,
24082                cx,
24083            );
24084            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24085            prompt.set_show_cursor_when_unfocused(false, cx);
24086            prompt.set_placeholder_text(
24087                match edit_action {
24088                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24089                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24090                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24091                },
24092                window,
24093                cx,
24094            );
24095
24096            prompt
24097        });
24098
24099        Self {
24100            prompt,
24101            editor,
24102            breakpoint_anchor,
24103            breakpoint,
24104            edit_action,
24105            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24106            block_ids: Default::default(),
24107            _subscriptions: vec![],
24108        }
24109    }
24110
24111    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24112        self.block_ids.extend(block_ids)
24113    }
24114
24115    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24116        if let Some(editor) = self.editor.upgrade() {
24117            let message = self
24118                .prompt
24119                .read(cx)
24120                .buffer
24121                .read(cx)
24122                .as_singleton()
24123                .expect("A multi buffer in breakpoint prompt isn't possible")
24124                .read(cx)
24125                .as_rope()
24126                .to_string();
24127
24128            editor.update(cx, |editor, cx| {
24129                editor.edit_breakpoint_at_anchor(
24130                    self.breakpoint_anchor,
24131                    self.breakpoint.clone(),
24132                    match self.edit_action {
24133                        BreakpointPromptEditAction::Log => {
24134                            BreakpointEditAction::EditLogMessage(message.into())
24135                        }
24136                        BreakpointPromptEditAction::Condition => {
24137                            BreakpointEditAction::EditCondition(message.into())
24138                        }
24139                        BreakpointPromptEditAction::HitCondition => {
24140                            BreakpointEditAction::EditHitCondition(message.into())
24141                        }
24142                    },
24143                    cx,
24144                );
24145
24146                editor.remove_blocks(self.block_ids.clone(), None, cx);
24147                cx.focus_self(window);
24148            });
24149        }
24150    }
24151
24152    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24153        self.editor
24154            .update(cx, |editor, cx| {
24155                editor.remove_blocks(self.block_ids.clone(), None, cx);
24156                window.focus(&editor.focus_handle);
24157            })
24158            .log_err();
24159    }
24160
24161    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24162        let settings = ThemeSettings::get_global(cx);
24163        let text_style = TextStyle {
24164            color: if self.prompt.read(cx).read_only(cx) {
24165                cx.theme().colors().text_disabled
24166            } else {
24167                cx.theme().colors().text
24168            },
24169            font_family: settings.buffer_font.family.clone(),
24170            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24171            font_size: settings.buffer_font_size(cx).into(),
24172            font_weight: settings.buffer_font.weight,
24173            line_height: relative(settings.buffer_line_height.value()),
24174            ..Default::default()
24175        };
24176        EditorElement::new(
24177            &self.prompt,
24178            EditorStyle {
24179                background: cx.theme().colors().editor_background,
24180                local_player: cx.theme().players().local(),
24181                text: text_style,
24182                ..Default::default()
24183            },
24184        )
24185    }
24186}
24187
24188impl Render for BreakpointPromptEditor {
24189    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24190        let editor_margins = *self.editor_margins.lock();
24191        let gutter_dimensions = editor_margins.gutter;
24192        h_flex()
24193            .key_context("Editor")
24194            .bg(cx.theme().colors().editor_background)
24195            .border_y_1()
24196            .border_color(cx.theme().status().info_border)
24197            .size_full()
24198            .py(window.line_height() / 2.5)
24199            .on_action(cx.listener(Self::confirm))
24200            .on_action(cx.listener(Self::cancel))
24201            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24202            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24203    }
24204}
24205
24206impl Focusable for BreakpointPromptEditor {
24207    fn focus_handle(&self, cx: &App) -> FocusHandle {
24208        self.prompt.focus_handle(cx)
24209    }
24210}
24211
24212fn all_edits_insertions_or_deletions(
24213    edits: &Vec<(Range<Anchor>, String)>,
24214    snapshot: &MultiBufferSnapshot,
24215) -> bool {
24216    let mut all_insertions = true;
24217    let mut all_deletions = true;
24218
24219    for (range, new_text) in edits.iter() {
24220        let range_is_empty = range.to_offset(snapshot).is_empty();
24221        let text_is_empty = new_text.is_empty();
24222
24223        if range_is_empty != text_is_empty {
24224            if range_is_empty {
24225                all_deletions = false;
24226            } else {
24227                all_insertions = false;
24228            }
24229        } else {
24230            return false;
24231        }
24232
24233        if !all_insertions && !all_deletions {
24234            return false;
24235        }
24236    }
24237    all_insertions || all_deletions
24238}
24239
24240struct MissingEditPredictionKeybindingTooltip;
24241
24242impl Render for MissingEditPredictionKeybindingTooltip {
24243    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24244        ui::tooltip_container(window, cx, |container, _, cx| {
24245            container
24246                .flex_shrink_0()
24247                .max_w_80()
24248                .min_h(rems_from_px(124.))
24249                .justify_between()
24250                .child(
24251                    v_flex()
24252                        .flex_1()
24253                        .text_ui_sm(cx)
24254                        .child(Label::new("Conflict with Accept Keybinding"))
24255                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24256                )
24257                .child(
24258                    h_flex()
24259                        .pb_1()
24260                        .gap_1()
24261                        .items_end()
24262                        .w_full()
24263                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24264                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24265                        }))
24266                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24267                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24268                        })),
24269                )
24270        })
24271    }
24272}
24273
24274#[derive(Debug, Clone, Copy, PartialEq)]
24275pub struct LineHighlight {
24276    pub background: Background,
24277    pub border: Option<gpui::Hsla>,
24278    pub include_gutter: bool,
24279    pub type_id: Option<TypeId>,
24280}
24281
24282struct LineManipulationResult {
24283    pub new_text: String,
24284    pub line_count_before: usize,
24285    pub line_count_after: usize,
24286}
24287
24288fn render_diff_hunk_controls(
24289    row: u32,
24290    status: &DiffHunkStatus,
24291    hunk_range: Range<Anchor>,
24292    is_created_file: bool,
24293    line_height: Pixels,
24294    editor: &Entity<Editor>,
24295    _window: &mut Window,
24296    cx: &mut App,
24297) -> AnyElement {
24298    h_flex()
24299        .h(line_height)
24300        .mr_1()
24301        .gap_1()
24302        .px_0p5()
24303        .pb_1()
24304        .border_x_1()
24305        .border_b_1()
24306        .border_color(cx.theme().colors().border_variant)
24307        .rounded_b_lg()
24308        .bg(cx.theme().colors().editor_background)
24309        .gap_1()
24310        .block_mouse_except_scroll()
24311        .shadow_md()
24312        .child(if status.has_secondary_hunk() {
24313            Button::new(("stage", row as u64), "Stage")
24314                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24315                .tooltip({
24316                    let focus_handle = editor.focus_handle(cx);
24317                    move |window, cx| {
24318                        Tooltip::for_action_in(
24319                            "Stage Hunk",
24320                            &::git::ToggleStaged,
24321                            &focus_handle,
24322                            window,
24323                            cx,
24324                        )
24325                    }
24326                })
24327                .on_click({
24328                    let editor = editor.clone();
24329                    move |_event, _window, cx| {
24330                        editor.update(cx, |editor, cx| {
24331                            editor.stage_or_unstage_diff_hunks(
24332                                true,
24333                                vec![hunk_range.start..hunk_range.start],
24334                                cx,
24335                            );
24336                        });
24337                    }
24338                })
24339        } else {
24340            Button::new(("unstage", row as u64), "Unstage")
24341                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24342                .tooltip({
24343                    let focus_handle = editor.focus_handle(cx);
24344                    move |window, cx| {
24345                        Tooltip::for_action_in(
24346                            "Unstage Hunk",
24347                            &::git::ToggleStaged,
24348                            &focus_handle,
24349                            window,
24350                            cx,
24351                        )
24352                    }
24353                })
24354                .on_click({
24355                    let editor = editor.clone();
24356                    move |_event, _window, cx| {
24357                        editor.update(cx, |editor, cx| {
24358                            editor.stage_or_unstage_diff_hunks(
24359                                false,
24360                                vec![hunk_range.start..hunk_range.start],
24361                                cx,
24362                            );
24363                        });
24364                    }
24365                })
24366        })
24367        .child(
24368            Button::new(("restore", row as u64), "Restore")
24369                .tooltip({
24370                    let focus_handle = editor.focus_handle(cx);
24371                    move |window, cx| {
24372                        Tooltip::for_action_in(
24373                            "Restore Hunk",
24374                            &::git::Restore,
24375                            &focus_handle,
24376                            window,
24377                            cx,
24378                        )
24379                    }
24380                })
24381                .on_click({
24382                    let editor = editor.clone();
24383                    move |_event, window, cx| {
24384                        editor.update(cx, |editor, cx| {
24385                            let snapshot = editor.snapshot(window, cx);
24386                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24387                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24388                        });
24389                    }
24390                })
24391                .disabled(is_created_file),
24392        )
24393        .when(
24394            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24395            |el| {
24396                el.child(
24397                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24398                        .shape(IconButtonShape::Square)
24399                        .icon_size(IconSize::Small)
24400                        // .disabled(!has_multiple_hunks)
24401                        .tooltip({
24402                            let focus_handle = editor.focus_handle(cx);
24403                            move |window, cx| {
24404                                Tooltip::for_action_in(
24405                                    "Next Hunk",
24406                                    &GoToHunk,
24407                                    &focus_handle,
24408                                    window,
24409                                    cx,
24410                                )
24411                            }
24412                        })
24413                        .on_click({
24414                            let editor = editor.clone();
24415                            move |_event, window, cx| {
24416                                editor.update(cx, |editor, cx| {
24417                                    let snapshot = editor.snapshot(window, cx);
24418                                    let position =
24419                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24420                                    editor.go_to_hunk_before_or_after_position(
24421                                        &snapshot,
24422                                        position,
24423                                        Direction::Next,
24424                                        window,
24425                                        cx,
24426                                    );
24427                                    editor.expand_selected_diff_hunks(cx);
24428                                });
24429                            }
24430                        }),
24431                )
24432                .child(
24433                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24434                        .shape(IconButtonShape::Square)
24435                        .icon_size(IconSize::Small)
24436                        // .disabled(!has_multiple_hunks)
24437                        .tooltip({
24438                            let focus_handle = editor.focus_handle(cx);
24439                            move |window, cx| {
24440                                Tooltip::for_action_in(
24441                                    "Previous Hunk",
24442                                    &GoToPreviousHunk,
24443                                    &focus_handle,
24444                                    window,
24445                                    cx,
24446                                )
24447                            }
24448                        })
24449                        .on_click({
24450                            let editor = editor.clone();
24451                            move |_event, window, cx| {
24452                                editor.update(cx, |editor, cx| {
24453                                    let snapshot = editor.snapshot(window, cx);
24454                                    let point =
24455                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24456                                    editor.go_to_hunk_before_or_after_position(
24457                                        &snapshot,
24458                                        point,
24459                                        Direction::Prev,
24460                                        window,
24461                                        cx,
24462                                    );
24463                                    editor.expand_selected_diff_hunks(cx);
24464                                });
24465                            }
24466                        }),
24467                )
24468            },
24469        )
24470        .into_any_element()
24471}
24472
24473pub fn multibuffer_context_lines(cx: &App) -> u32 {
24474    EditorSettings::try_get(cx)
24475        .map(|settings| settings.excerpt_context_lines)
24476        .unwrap_or(2)
24477        .min(32)
24478}