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
21681fn vim_enabled(cx: &App) -> bool {
21682    vim_mode_setting::VimModeSetting::try_get(cx)
21683        .map(|vim_mode| vim_mode.0)
21684        .unwrap_or(false)
21685}
21686
21687fn process_completion_for_edit(
21688    completion: &Completion,
21689    intent: CompletionIntent,
21690    buffer: &Entity<Buffer>,
21691    cursor_position: &text::Anchor,
21692    cx: &mut Context<Editor>,
21693) -> CompletionEdit {
21694    let buffer = buffer.read(cx);
21695    let buffer_snapshot = buffer.snapshot();
21696    let (snippet, new_text) = if completion.is_snippet() {
21697        // Workaround for typescript language server issues so that methods don't expand within
21698        // strings and functions with type expressions. The previous point is used because the query
21699        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21700        let mut snippet_source = completion.new_text.clone();
21701        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21702        previous_point.column = previous_point.column.saturating_sub(1);
21703        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21704            && scope.prefers_label_for_snippet_in_completion()
21705            && let Some(label) = completion.label()
21706            && matches!(
21707                completion.kind(),
21708                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21709            )
21710        {
21711            snippet_source = label;
21712        }
21713        match Snippet::parse(&snippet_source).log_err() {
21714            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21715            None => (None, completion.new_text.clone()),
21716        }
21717    } else {
21718        (None, completion.new_text.clone())
21719    };
21720
21721    let mut range_to_replace = {
21722        let replace_range = &completion.replace_range;
21723        if let CompletionSource::Lsp {
21724            insert_range: Some(insert_range),
21725            ..
21726        } = &completion.source
21727        {
21728            debug_assert_eq!(
21729                insert_range.start, replace_range.start,
21730                "insert_range and replace_range should start at the same position"
21731            );
21732            debug_assert!(
21733                insert_range
21734                    .start
21735                    .cmp(cursor_position, &buffer_snapshot)
21736                    .is_le(),
21737                "insert_range should start before or at cursor position"
21738            );
21739            debug_assert!(
21740                replace_range
21741                    .start
21742                    .cmp(cursor_position, &buffer_snapshot)
21743                    .is_le(),
21744                "replace_range should start before or at cursor position"
21745            );
21746
21747            let should_replace = match intent {
21748                CompletionIntent::CompleteWithInsert => false,
21749                CompletionIntent::CompleteWithReplace => true,
21750                CompletionIntent::Complete | CompletionIntent::Compose => {
21751                    let insert_mode =
21752                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21753                            .completions
21754                            .lsp_insert_mode;
21755                    match insert_mode {
21756                        LspInsertMode::Insert => false,
21757                        LspInsertMode::Replace => true,
21758                        LspInsertMode::ReplaceSubsequence => {
21759                            let mut text_to_replace = buffer.chars_for_range(
21760                                buffer.anchor_before(replace_range.start)
21761                                    ..buffer.anchor_after(replace_range.end),
21762                            );
21763                            let mut current_needle = text_to_replace.next();
21764                            for haystack_ch in completion.label.text.chars() {
21765                                if let Some(needle_ch) = current_needle
21766                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21767                                {
21768                                    current_needle = text_to_replace.next();
21769                                }
21770                            }
21771                            current_needle.is_none()
21772                        }
21773                        LspInsertMode::ReplaceSuffix => {
21774                            if replace_range
21775                                .end
21776                                .cmp(cursor_position, &buffer_snapshot)
21777                                .is_gt()
21778                            {
21779                                let range_after_cursor = *cursor_position..replace_range.end;
21780                                let text_after_cursor = buffer
21781                                    .text_for_range(
21782                                        buffer.anchor_before(range_after_cursor.start)
21783                                            ..buffer.anchor_after(range_after_cursor.end),
21784                                    )
21785                                    .collect::<String>()
21786                                    .to_ascii_lowercase();
21787                                completion
21788                                    .label
21789                                    .text
21790                                    .to_ascii_lowercase()
21791                                    .ends_with(&text_after_cursor)
21792                            } else {
21793                                true
21794                            }
21795                        }
21796                    }
21797                }
21798            };
21799
21800            if should_replace {
21801                replace_range.clone()
21802            } else {
21803                insert_range.clone()
21804            }
21805        } else {
21806            replace_range.clone()
21807        }
21808    };
21809
21810    if range_to_replace
21811        .end
21812        .cmp(cursor_position, &buffer_snapshot)
21813        .is_lt()
21814    {
21815        range_to_replace.end = *cursor_position;
21816    }
21817
21818    CompletionEdit {
21819        new_text,
21820        replace_range: range_to_replace.to_offset(buffer),
21821        snippet,
21822    }
21823}
21824
21825struct CompletionEdit {
21826    new_text: String,
21827    replace_range: Range<usize>,
21828    snippet: Option<Snippet>,
21829}
21830
21831fn insert_extra_newline_brackets(
21832    buffer: &MultiBufferSnapshot,
21833    range: Range<usize>,
21834    language: &language::LanguageScope,
21835) -> bool {
21836    let leading_whitespace_len = buffer
21837        .reversed_chars_at(range.start)
21838        .take_while(|c| c.is_whitespace() && *c != '\n')
21839        .map(|c| c.len_utf8())
21840        .sum::<usize>();
21841    let trailing_whitespace_len = buffer
21842        .chars_at(range.end)
21843        .take_while(|c| c.is_whitespace() && *c != '\n')
21844        .map(|c| c.len_utf8())
21845        .sum::<usize>();
21846    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21847
21848    language.brackets().any(|(pair, enabled)| {
21849        let pair_start = pair.start.trim_end();
21850        let pair_end = pair.end.trim_start();
21851
21852        enabled
21853            && pair.newline
21854            && buffer.contains_str_at(range.end, pair_end)
21855            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21856    })
21857}
21858
21859fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21860    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21861        [(buffer, range, _)] => (*buffer, range.clone()),
21862        _ => return false,
21863    };
21864    let pair = {
21865        let mut result: Option<BracketMatch> = None;
21866
21867        for pair in buffer
21868            .all_bracket_ranges(range.clone())
21869            .filter(move |pair| {
21870                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21871            })
21872        {
21873            let len = pair.close_range.end - pair.open_range.start;
21874
21875            if let Some(existing) = &result {
21876                let existing_len = existing.close_range.end - existing.open_range.start;
21877                if len > existing_len {
21878                    continue;
21879                }
21880            }
21881
21882            result = Some(pair);
21883        }
21884
21885        result
21886    };
21887    let Some(pair) = pair else {
21888        return false;
21889    };
21890    pair.newline_only
21891        && buffer
21892            .chars_for_range(pair.open_range.end..range.start)
21893            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21894            .all(|c| c.is_whitespace() && c != '\n')
21895}
21896
21897fn update_uncommitted_diff_for_buffer(
21898    editor: Entity<Editor>,
21899    project: &Entity<Project>,
21900    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21901    buffer: Entity<MultiBuffer>,
21902    cx: &mut App,
21903) -> Task<()> {
21904    let mut tasks = Vec::new();
21905    project.update(cx, |project, cx| {
21906        for buffer in buffers {
21907            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21908                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21909            }
21910        }
21911    });
21912    cx.spawn(async move |cx| {
21913        let diffs = future::join_all(tasks).await;
21914        if editor
21915            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21916            .unwrap_or(false)
21917        {
21918            return;
21919        }
21920
21921        buffer
21922            .update(cx, |buffer, cx| {
21923                for diff in diffs.into_iter().flatten() {
21924                    buffer.add_diff(diff, cx);
21925                }
21926            })
21927            .ok();
21928    })
21929}
21930
21931fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21932    let tab_size = tab_size.get() as usize;
21933    let mut width = offset;
21934
21935    for ch in text.chars() {
21936        width += if ch == '\t' {
21937            tab_size - (width % tab_size)
21938        } else {
21939            1
21940        };
21941    }
21942
21943    width - offset
21944}
21945
21946#[cfg(test)]
21947mod tests {
21948    use super::*;
21949
21950    #[test]
21951    fn test_string_size_with_expanded_tabs() {
21952        let nz = |val| NonZeroU32::new(val).unwrap();
21953        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21954        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21955        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21956        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21957        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21958        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21959        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21960        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21961    }
21962}
21963
21964/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21965struct WordBreakingTokenizer<'a> {
21966    input: &'a str,
21967}
21968
21969impl<'a> WordBreakingTokenizer<'a> {
21970    fn new(input: &'a str) -> Self {
21971        Self { input }
21972    }
21973}
21974
21975fn is_char_ideographic(ch: char) -> bool {
21976    use unicode_script::Script::*;
21977    use unicode_script::UnicodeScript;
21978    matches!(ch.script(), Han | Tangut | Yi)
21979}
21980
21981fn is_grapheme_ideographic(text: &str) -> bool {
21982    text.chars().any(is_char_ideographic)
21983}
21984
21985fn is_grapheme_whitespace(text: &str) -> bool {
21986    text.chars().any(|x| x.is_whitespace())
21987}
21988
21989fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21990    text.chars()
21991        .next()
21992        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21993}
21994
21995#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21996enum WordBreakToken<'a> {
21997    Word { token: &'a str, grapheme_len: usize },
21998    InlineWhitespace { token: &'a str, grapheme_len: usize },
21999    Newline,
22000}
22001
22002impl<'a> Iterator for WordBreakingTokenizer<'a> {
22003    /// Yields a span, the count of graphemes in the token, and whether it was
22004    /// whitespace. Note that it also breaks at word boundaries.
22005    type Item = WordBreakToken<'a>;
22006
22007    fn next(&mut self) -> Option<Self::Item> {
22008        use unicode_segmentation::UnicodeSegmentation;
22009        if self.input.is_empty() {
22010            return None;
22011        }
22012
22013        let mut iter = self.input.graphemes(true).peekable();
22014        let mut offset = 0;
22015        let mut grapheme_len = 0;
22016        if let Some(first_grapheme) = iter.next() {
22017            let is_newline = first_grapheme == "\n";
22018            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22019            offset += first_grapheme.len();
22020            grapheme_len += 1;
22021            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22022                if let Some(grapheme) = iter.peek().copied()
22023                    && should_stay_with_preceding_ideograph(grapheme)
22024                {
22025                    offset += grapheme.len();
22026                    grapheme_len += 1;
22027                }
22028            } else {
22029                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22030                let mut next_word_bound = words.peek().copied();
22031                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22032                    next_word_bound = words.next();
22033                }
22034                while let Some(grapheme) = iter.peek().copied() {
22035                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22036                        break;
22037                    };
22038                    if is_grapheme_whitespace(grapheme) != is_whitespace
22039                        || (grapheme == "\n") != is_newline
22040                    {
22041                        break;
22042                    };
22043                    offset += grapheme.len();
22044                    grapheme_len += 1;
22045                    iter.next();
22046                }
22047            }
22048            let token = &self.input[..offset];
22049            self.input = &self.input[offset..];
22050            if token == "\n" {
22051                Some(WordBreakToken::Newline)
22052            } else if is_whitespace {
22053                Some(WordBreakToken::InlineWhitespace {
22054                    token,
22055                    grapheme_len,
22056                })
22057            } else {
22058                Some(WordBreakToken::Word {
22059                    token,
22060                    grapheme_len,
22061                })
22062            }
22063        } else {
22064            None
22065        }
22066    }
22067}
22068
22069#[test]
22070fn test_word_breaking_tokenizer() {
22071    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22072        ("", &[]),
22073        ("  ", &[whitespace("  ", 2)]),
22074        ("Ʒ", &[word("Ʒ", 1)]),
22075        ("Ǽ", &[word("Ǽ", 1)]),
22076        ("", &[word("", 1)]),
22077        ("⋑⋑", &[word("⋑⋑", 2)]),
22078        (
22079            "原理,进而",
22080            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22081        ),
22082        (
22083            "hello world",
22084            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22085        ),
22086        (
22087            "hello, world",
22088            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22089        ),
22090        (
22091            "  hello world",
22092            &[
22093                whitespace("  ", 2),
22094                word("hello", 5),
22095                whitespace(" ", 1),
22096                word("world", 5),
22097            ],
22098        ),
22099        (
22100            "这是什么 \n 钢笔",
22101            &[
22102                word("", 1),
22103                word("", 1),
22104                word("", 1),
22105                word("", 1),
22106                whitespace(" ", 1),
22107                newline(),
22108                whitespace(" ", 1),
22109                word("", 1),
22110                word("", 1),
22111            ],
22112        ),
22113        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22114    ];
22115
22116    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22117        WordBreakToken::Word {
22118            token,
22119            grapheme_len,
22120        }
22121    }
22122
22123    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22124        WordBreakToken::InlineWhitespace {
22125            token,
22126            grapheme_len,
22127        }
22128    }
22129
22130    fn newline() -> WordBreakToken<'static> {
22131        WordBreakToken::Newline
22132    }
22133
22134    for (input, result) in tests {
22135        assert_eq!(
22136            WordBreakingTokenizer::new(input)
22137                .collect::<Vec<_>>()
22138                .as_slice(),
22139            *result,
22140        );
22141    }
22142}
22143
22144fn wrap_with_prefix(
22145    first_line_prefix: String,
22146    subsequent_lines_prefix: String,
22147    unwrapped_text: String,
22148    wrap_column: usize,
22149    tab_size: NonZeroU32,
22150    preserve_existing_whitespace: bool,
22151) -> String {
22152    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22153    let subsequent_lines_prefix_len =
22154        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22155    let mut wrapped_text = String::new();
22156    let mut current_line = first_line_prefix;
22157    let mut is_first_line = true;
22158
22159    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22160    let mut current_line_len = first_line_prefix_len;
22161    let mut in_whitespace = false;
22162    for token in tokenizer {
22163        let have_preceding_whitespace = in_whitespace;
22164        match token {
22165            WordBreakToken::Word {
22166                token,
22167                grapheme_len,
22168            } => {
22169                in_whitespace = false;
22170                let current_prefix_len = if is_first_line {
22171                    first_line_prefix_len
22172                } else {
22173                    subsequent_lines_prefix_len
22174                };
22175                if current_line_len + grapheme_len > wrap_column
22176                    && current_line_len != current_prefix_len
22177                {
22178                    wrapped_text.push_str(current_line.trim_end());
22179                    wrapped_text.push('\n');
22180                    is_first_line = false;
22181                    current_line = subsequent_lines_prefix.clone();
22182                    current_line_len = subsequent_lines_prefix_len;
22183                }
22184                current_line.push_str(token);
22185                current_line_len += grapheme_len;
22186            }
22187            WordBreakToken::InlineWhitespace {
22188                mut token,
22189                mut grapheme_len,
22190            } => {
22191                in_whitespace = true;
22192                if have_preceding_whitespace && !preserve_existing_whitespace {
22193                    continue;
22194                }
22195                if !preserve_existing_whitespace {
22196                    token = " ";
22197                    grapheme_len = 1;
22198                }
22199                let current_prefix_len = if is_first_line {
22200                    first_line_prefix_len
22201                } else {
22202                    subsequent_lines_prefix_len
22203                };
22204                if current_line_len + grapheme_len > wrap_column {
22205                    wrapped_text.push_str(current_line.trim_end());
22206                    wrapped_text.push('\n');
22207                    is_first_line = false;
22208                    current_line = subsequent_lines_prefix.clone();
22209                    current_line_len = subsequent_lines_prefix_len;
22210                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22211                    current_line.push_str(token);
22212                    current_line_len += grapheme_len;
22213                }
22214            }
22215            WordBreakToken::Newline => {
22216                in_whitespace = true;
22217                let current_prefix_len = if is_first_line {
22218                    first_line_prefix_len
22219                } else {
22220                    subsequent_lines_prefix_len
22221                };
22222                if preserve_existing_whitespace {
22223                    wrapped_text.push_str(current_line.trim_end());
22224                    wrapped_text.push('\n');
22225                    is_first_line = false;
22226                    current_line = subsequent_lines_prefix.clone();
22227                    current_line_len = subsequent_lines_prefix_len;
22228                } else if have_preceding_whitespace {
22229                    continue;
22230                } else if current_line_len + 1 > wrap_column
22231                    && current_line_len != current_prefix_len
22232                {
22233                    wrapped_text.push_str(current_line.trim_end());
22234                    wrapped_text.push('\n');
22235                    is_first_line = false;
22236                    current_line = subsequent_lines_prefix.clone();
22237                    current_line_len = subsequent_lines_prefix_len;
22238                } else if current_line_len != current_prefix_len {
22239                    current_line.push(' ');
22240                    current_line_len += 1;
22241                }
22242            }
22243        }
22244    }
22245
22246    if !current_line.is_empty() {
22247        wrapped_text.push_str(&current_line);
22248    }
22249    wrapped_text
22250}
22251
22252#[test]
22253fn test_wrap_with_prefix() {
22254    assert_eq!(
22255        wrap_with_prefix(
22256            "# ".to_string(),
22257            "# ".to_string(),
22258            "abcdefg".to_string(),
22259            4,
22260            NonZeroU32::new(4).unwrap(),
22261            false,
22262        ),
22263        "# abcdefg"
22264    );
22265    assert_eq!(
22266        wrap_with_prefix(
22267            "".to_string(),
22268            "".to_string(),
22269            "\thello world".to_string(),
22270            8,
22271            NonZeroU32::new(4).unwrap(),
22272            false,
22273        ),
22274        "hello\nworld"
22275    );
22276    assert_eq!(
22277        wrap_with_prefix(
22278            "// ".to_string(),
22279            "// ".to_string(),
22280            "xx \nyy zz aa bb cc".to_string(),
22281            12,
22282            NonZeroU32::new(4).unwrap(),
22283            false,
22284        ),
22285        "// xx yy zz\n// aa bb cc"
22286    );
22287    assert_eq!(
22288        wrap_with_prefix(
22289            String::new(),
22290            String::new(),
22291            "这是什么 \n 钢笔".to_string(),
22292            3,
22293            NonZeroU32::new(4).unwrap(),
22294            false,
22295        ),
22296        "这是什\n么 钢\n"
22297    );
22298}
22299
22300pub trait CollaborationHub {
22301    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22302    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22303    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22304}
22305
22306impl CollaborationHub for Entity<Project> {
22307    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22308        self.read(cx).collaborators()
22309    }
22310
22311    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22312        self.read(cx).user_store().read(cx).participant_indices()
22313    }
22314
22315    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22316        let this = self.read(cx);
22317        let user_ids = this.collaborators().values().map(|c| c.user_id);
22318        this.user_store().read(cx).participant_names(user_ids, cx)
22319    }
22320}
22321
22322pub trait SemanticsProvider {
22323    fn hover(
22324        &self,
22325        buffer: &Entity<Buffer>,
22326        position: text::Anchor,
22327        cx: &mut App,
22328    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22329
22330    fn inline_values(
22331        &self,
22332        buffer_handle: Entity<Buffer>,
22333        range: Range<text::Anchor>,
22334        cx: &mut App,
22335    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22336
22337    fn inlay_hints(
22338        &self,
22339        buffer_handle: Entity<Buffer>,
22340        range: Range<text::Anchor>,
22341        cx: &mut App,
22342    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22343
22344    fn resolve_inlay_hint(
22345        &self,
22346        hint: InlayHint,
22347        buffer_handle: Entity<Buffer>,
22348        server_id: LanguageServerId,
22349        cx: &mut App,
22350    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22351
22352    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22353
22354    fn document_highlights(
22355        &self,
22356        buffer: &Entity<Buffer>,
22357        position: text::Anchor,
22358        cx: &mut App,
22359    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22360
22361    fn definitions(
22362        &self,
22363        buffer: &Entity<Buffer>,
22364        position: text::Anchor,
22365        kind: GotoDefinitionKind,
22366        cx: &mut App,
22367    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22368
22369    fn range_for_rename(
22370        &self,
22371        buffer: &Entity<Buffer>,
22372        position: text::Anchor,
22373        cx: &mut App,
22374    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22375
22376    fn perform_rename(
22377        &self,
22378        buffer: &Entity<Buffer>,
22379        position: text::Anchor,
22380        new_name: String,
22381        cx: &mut App,
22382    ) -> Option<Task<Result<ProjectTransaction>>>;
22383}
22384
22385pub trait CompletionProvider {
22386    fn completions(
22387        &self,
22388        excerpt_id: ExcerptId,
22389        buffer: &Entity<Buffer>,
22390        buffer_position: text::Anchor,
22391        trigger: CompletionContext,
22392        window: &mut Window,
22393        cx: &mut Context<Editor>,
22394    ) -> Task<Result<Vec<CompletionResponse>>>;
22395
22396    fn resolve_completions(
22397        &self,
22398        _buffer: Entity<Buffer>,
22399        _completion_indices: Vec<usize>,
22400        _completions: Rc<RefCell<Box<[Completion]>>>,
22401        _cx: &mut Context<Editor>,
22402    ) -> Task<Result<bool>> {
22403        Task::ready(Ok(false))
22404    }
22405
22406    fn apply_additional_edits_for_completion(
22407        &self,
22408        _buffer: Entity<Buffer>,
22409        _completions: Rc<RefCell<Box<[Completion]>>>,
22410        _completion_index: usize,
22411        _push_to_history: bool,
22412        _cx: &mut Context<Editor>,
22413    ) -> Task<Result<Option<language::Transaction>>> {
22414        Task::ready(Ok(None))
22415    }
22416
22417    fn is_completion_trigger(
22418        &self,
22419        buffer: &Entity<Buffer>,
22420        position: language::Anchor,
22421        text: &str,
22422        trigger_in_words: bool,
22423        menu_is_open: bool,
22424        cx: &mut Context<Editor>,
22425    ) -> bool;
22426
22427    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22428
22429    fn sort_completions(&self) -> bool {
22430        true
22431    }
22432
22433    fn filter_completions(&self) -> bool {
22434        true
22435    }
22436}
22437
22438pub trait CodeActionProvider {
22439    fn id(&self) -> Arc<str>;
22440
22441    fn code_actions(
22442        &self,
22443        buffer: &Entity<Buffer>,
22444        range: Range<text::Anchor>,
22445        window: &mut Window,
22446        cx: &mut App,
22447    ) -> Task<Result<Vec<CodeAction>>>;
22448
22449    fn apply_code_action(
22450        &self,
22451        buffer_handle: Entity<Buffer>,
22452        action: CodeAction,
22453        excerpt_id: ExcerptId,
22454        push_to_history: bool,
22455        window: &mut Window,
22456        cx: &mut App,
22457    ) -> Task<Result<ProjectTransaction>>;
22458}
22459
22460impl CodeActionProvider for Entity<Project> {
22461    fn id(&self) -> Arc<str> {
22462        "project".into()
22463    }
22464
22465    fn code_actions(
22466        &self,
22467        buffer: &Entity<Buffer>,
22468        range: Range<text::Anchor>,
22469        _window: &mut Window,
22470        cx: &mut App,
22471    ) -> Task<Result<Vec<CodeAction>>> {
22472        self.update(cx, |project, cx| {
22473            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22474            let code_actions = project.code_actions(buffer, range, None, cx);
22475            cx.background_spawn(async move {
22476                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22477                Ok(code_lens_actions
22478                    .context("code lens fetch")?
22479                    .into_iter()
22480                    .flatten()
22481                    .chain(
22482                        code_actions
22483                            .context("code action fetch")?
22484                            .into_iter()
22485                            .flatten(),
22486                    )
22487                    .collect())
22488            })
22489        })
22490    }
22491
22492    fn apply_code_action(
22493        &self,
22494        buffer_handle: Entity<Buffer>,
22495        action: CodeAction,
22496        _excerpt_id: ExcerptId,
22497        push_to_history: bool,
22498        _window: &mut Window,
22499        cx: &mut App,
22500    ) -> Task<Result<ProjectTransaction>> {
22501        self.update(cx, |project, cx| {
22502            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22503        })
22504    }
22505}
22506
22507fn snippet_completions(
22508    project: &Project,
22509    buffer: &Entity<Buffer>,
22510    buffer_position: text::Anchor,
22511    cx: &mut App,
22512) -> Task<Result<CompletionResponse>> {
22513    let languages = buffer.read(cx).languages_at(buffer_position);
22514    let snippet_store = project.snippets().read(cx);
22515
22516    let scopes: Vec<_> = languages
22517        .iter()
22518        .filter_map(|language| {
22519            let language_name = language.lsp_id();
22520            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22521
22522            if snippets.is_empty() {
22523                None
22524            } else {
22525                Some((language.default_scope(), snippets))
22526            }
22527        })
22528        .collect();
22529
22530    if scopes.is_empty() {
22531        return Task::ready(Ok(CompletionResponse {
22532            completions: vec![],
22533            display_options: CompletionDisplayOptions::default(),
22534            is_incomplete: false,
22535        }));
22536    }
22537
22538    let snapshot = buffer.read(cx).text_snapshot();
22539    let chars: String = snapshot
22540        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22541        .collect();
22542    let executor = cx.background_executor().clone();
22543
22544    cx.background_spawn(async move {
22545        let mut is_incomplete = false;
22546        let mut completions: Vec<Completion> = Vec::new();
22547        for (scope, snippets) in scopes.into_iter() {
22548            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22549            let mut last_word = chars
22550                .chars()
22551                .take_while(|c| classifier.is_word(*c))
22552                .collect::<String>();
22553            last_word = last_word.chars().rev().collect();
22554
22555            if last_word.is_empty() {
22556                return Ok(CompletionResponse {
22557                    completions: vec![],
22558                    display_options: CompletionDisplayOptions::default(),
22559                    is_incomplete: true,
22560                });
22561            }
22562
22563            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22564            let to_lsp = |point: &text::Anchor| {
22565                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22566                point_to_lsp(end)
22567            };
22568            let lsp_end = to_lsp(&buffer_position);
22569
22570            let candidates = snippets
22571                .iter()
22572                .enumerate()
22573                .flat_map(|(ix, snippet)| {
22574                    snippet
22575                        .prefix
22576                        .iter()
22577                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22578                })
22579                .collect::<Vec<StringMatchCandidate>>();
22580
22581            const MAX_RESULTS: usize = 100;
22582            let mut matches = fuzzy::match_strings(
22583                &candidates,
22584                &last_word,
22585                last_word.chars().any(|c| c.is_uppercase()),
22586                true,
22587                MAX_RESULTS,
22588                &Default::default(),
22589                executor.clone(),
22590            )
22591            .await;
22592
22593            if matches.len() >= MAX_RESULTS {
22594                is_incomplete = true;
22595            }
22596
22597            // Remove all candidates where the query's start does not match the start of any word in the candidate
22598            if let Some(query_start) = last_word.chars().next() {
22599                matches.retain(|string_match| {
22600                    split_words(&string_match.string).any(|word| {
22601                        // Check that the first codepoint of the word as lowercase matches the first
22602                        // codepoint of the query as lowercase
22603                        word.chars()
22604                            .flat_map(|codepoint| codepoint.to_lowercase())
22605                            .zip(query_start.to_lowercase())
22606                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22607                    })
22608                });
22609            }
22610
22611            let matched_strings = matches
22612                .into_iter()
22613                .map(|m| m.string)
22614                .collect::<HashSet<_>>();
22615
22616            completions.extend(snippets.iter().filter_map(|snippet| {
22617                let matching_prefix = snippet
22618                    .prefix
22619                    .iter()
22620                    .find(|prefix| matched_strings.contains(*prefix))?;
22621                let start = as_offset - last_word.len();
22622                let start = snapshot.anchor_before(start);
22623                let range = start..buffer_position;
22624                let lsp_start = to_lsp(&start);
22625                let lsp_range = lsp::Range {
22626                    start: lsp_start,
22627                    end: lsp_end,
22628                };
22629                Some(Completion {
22630                    replace_range: range,
22631                    new_text: snippet.body.clone(),
22632                    source: CompletionSource::Lsp {
22633                        insert_range: None,
22634                        server_id: LanguageServerId(usize::MAX),
22635                        resolved: true,
22636                        lsp_completion: Box::new(lsp::CompletionItem {
22637                            label: snippet.prefix.first().unwrap().clone(),
22638                            kind: Some(CompletionItemKind::SNIPPET),
22639                            label_details: snippet.description.as_ref().map(|description| {
22640                                lsp::CompletionItemLabelDetails {
22641                                    detail: Some(description.clone()),
22642                                    description: None,
22643                                }
22644                            }),
22645                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22646                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22647                                lsp::InsertReplaceEdit {
22648                                    new_text: snippet.body.clone(),
22649                                    insert: lsp_range,
22650                                    replace: lsp_range,
22651                                },
22652                            )),
22653                            filter_text: Some(snippet.body.clone()),
22654                            sort_text: Some(char::MAX.to_string()),
22655                            ..lsp::CompletionItem::default()
22656                        }),
22657                        lsp_defaults: None,
22658                    },
22659                    label: CodeLabel {
22660                        text: matching_prefix.clone(),
22661                        runs: Vec::new(),
22662                        filter_range: 0..matching_prefix.len(),
22663                    },
22664                    icon_path: None,
22665                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22666                        single_line: snippet.name.clone().into(),
22667                        plain_text: snippet
22668                            .description
22669                            .clone()
22670                            .map(|description| description.into()),
22671                    }),
22672                    insert_text_mode: None,
22673                    confirm: None,
22674                })
22675            }))
22676        }
22677
22678        Ok(CompletionResponse {
22679            completions,
22680            display_options: CompletionDisplayOptions::default(),
22681            is_incomplete,
22682        })
22683    })
22684}
22685
22686impl CompletionProvider for Entity<Project> {
22687    fn completions(
22688        &self,
22689        _excerpt_id: ExcerptId,
22690        buffer: &Entity<Buffer>,
22691        buffer_position: text::Anchor,
22692        options: CompletionContext,
22693        _window: &mut Window,
22694        cx: &mut Context<Editor>,
22695    ) -> Task<Result<Vec<CompletionResponse>>> {
22696        self.update(cx, |project, cx| {
22697            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22698            let project_completions = project.completions(buffer, buffer_position, options, cx);
22699            cx.background_spawn(async move {
22700                let mut responses = project_completions.await?;
22701                let snippets = snippets.await?;
22702                if !snippets.completions.is_empty() {
22703                    responses.push(snippets);
22704                }
22705                Ok(responses)
22706            })
22707        })
22708    }
22709
22710    fn resolve_completions(
22711        &self,
22712        buffer: Entity<Buffer>,
22713        completion_indices: Vec<usize>,
22714        completions: Rc<RefCell<Box<[Completion]>>>,
22715        cx: &mut Context<Editor>,
22716    ) -> Task<Result<bool>> {
22717        self.update(cx, |project, cx| {
22718            project.lsp_store().update(cx, |lsp_store, cx| {
22719                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22720            })
22721        })
22722    }
22723
22724    fn apply_additional_edits_for_completion(
22725        &self,
22726        buffer: Entity<Buffer>,
22727        completions: Rc<RefCell<Box<[Completion]>>>,
22728        completion_index: usize,
22729        push_to_history: bool,
22730        cx: &mut Context<Editor>,
22731    ) -> Task<Result<Option<language::Transaction>>> {
22732        self.update(cx, |project, cx| {
22733            project.lsp_store().update(cx, |lsp_store, cx| {
22734                lsp_store.apply_additional_edits_for_completion(
22735                    buffer,
22736                    completions,
22737                    completion_index,
22738                    push_to_history,
22739                    cx,
22740                )
22741            })
22742        })
22743    }
22744
22745    fn is_completion_trigger(
22746        &self,
22747        buffer: &Entity<Buffer>,
22748        position: language::Anchor,
22749        text: &str,
22750        trigger_in_words: bool,
22751        menu_is_open: bool,
22752        cx: &mut Context<Editor>,
22753    ) -> bool {
22754        let mut chars = text.chars();
22755        let char = if let Some(char) = chars.next() {
22756            char
22757        } else {
22758            return false;
22759        };
22760        if chars.next().is_some() {
22761            return false;
22762        }
22763
22764        let buffer = buffer.read(cx);
22765        let snapshot = buffer.snapshot();
22766        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22767            return false;
22768        }
22769        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22770        if trigger_in_words && classifier.is_word(char) {
22771            return true;
22772        }
22773
22774        buffer.completion_triggers().contains(text)
22775    }
22776}
22777
22778impl SemanticsProvider for Entity<Project> {
22779    fn hover(
22780        &self,
22781        buffer: &Entity<Buffer>,
22782        position: text::Anchor,
22783        cx: &mut App,
22784    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22785        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22786    }
22787
22788    fn document_highlights(
22789        &self,
22790        buffer: &Entity<Buffer>,
22791        position: text::Anchor,
22792        cx: &mut App,
22793    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22794        Some(self.update(cx, |project, cx| {
22795            project.document_highlights(buffer, position, cx)
22796        }))
22797    }
22798
22799    fn definitions(
22800        &self,
22801        buffer: &Entity<Buffer>,
22802        position: text::Anchor,
22803        kind: GotoDefinitionKind,
22804        cx: &mut App,
22805    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22806        Some(self.update(cx, |project, cx| match kind {
22807            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22808            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22809            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22810            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22811        }))
22812    }
22813
22814    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22815        self.update(cx, |project, cx| {
22816            if project
22817                .active_debug_session(cx)
22818                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22819            {
22820                return true;
22821            }
22822
22823            buffer.update(cx, |buffer, cx| {
22824                project.any_language_server_supports_inlay_hints(buffer, cx)
22825            })
22826        })
22827    }
22828
22829    fn inline_values(
22830        &self,
22831        buffer_handle: Entity<Buffer>,
22832        range: Range<text::Anchor>,
22833        cx: &mut App,
22834    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22835        self.update(cx, |project, cx| {
22836            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22837
22838            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22839        })
22840    }
22841
22842    fn inlay_hints(
22843        &self,
22844        buffer_handle: Entity<Buffer>,
22845        range: Range<text::Anchor>,
22846        cx: &mut App,
22847    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22848        Some(self.update(cx, |project, cx| {
22849            project.inlay_hints(buffer_handle, range, cx)
22850        }))
22851    }
22852
22853    fn resolve_inlay_hint(
22854        &self,
22855        hint: InlayHint,
22856        buffer_handle: Entity<Buffer>,
22857        server_id: LanguageServerId,
22858        cx: &mut App,
22859    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22860        Some(self.update(cx, |project, cx| {
22861            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22862        }))
22863    }
22864
22865    fn range_for_rename(
22866        &self,
22867        buffer: &Entity<Buffer>,
22868        position: text::Anchor,
22869        cx: &mut App,
22870    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22871        Some(self.update(cx, |project, cx| {
22872            let buffer = buffer.clone();
22873            let task = project.prepare_rename(buffer.clone(), position, cx);
22874            cx.spawn(async move |_, cx| {
22875                Ok(match task.await? {
22876                    PrepareRenameResponse::Success(range) => Some(range),
22877                    PrepareRenameResponse::InvalidPosition => None,
22878                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22879                        // Fallback on using TreeSitter info to determine identifier range
22880                        buffer.read_with(cx, |buffer, _| {
22881                            let snapshot = buffer.snapshot();
22882                            let (range, kind) = snapshot.surrounding_word(position, false);
22883                            if kind != Some(CharKind::Word) {
22884                                return None;
22885                            }
22886                            Some(
22887                                snapshot.anchor_before(range.start)
22888                                    ..snapshot.anchor_after(range.end),
22889                            )
22890                        })?
22891                    }
22892                })
22893            })
22894        }))
22895    }
22896
22897    fn perform_rename(
22898        &self,
22899        buffer: &Entity<Buffer>,
22900        position: text::Anchor,
22901        new_name: String,
22902        cx: &mut App,
22903    ) -> Option<Task<Result<ProjectTransaction>>> {
22904        Some(self.update(cx, |project, cx| {
22905            project.perform_rename(buffer.clone(), position, new_name, cx)
22906        }))
22907    }
22908}
22909
22910fn inlay_hint_settings(
22911    location: Anchor,
22912    snapshot: &MultiBufferSnapshot,
22913    cx: &mut Context<Editor>,
22914) -> InlayHintSettings {
22915    let file = snapshot.file_at(location);
22916    let language = snapshot.language_at(location).map(|l| l.name());
22917    language_settings(language, file, cx).inlay_hints
22918}
22919
22920fn consume_contiguous_rows(
22921    contiguous_row_selections: &mut Vec<Selection<Point>>,
22922    selection: &Selection<Point>,
22923    display_map: &DisplaySnapshot,
22924    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22925) -> (MultiBufferRow, MultiBufferRow) {
22926    contiguous_row_selections.push(selection.clone());
22927    let start_row = starting_row(selection, display_map);
22928    let mut end_row = ending_row(selection, display_map);
22929
22930    while let Some(next_selection) = selections.peek() {
22931        if next_selection.start.row <= end_row.0 {
22932            end_row = ending_row(next_selection, display_map);
22933            contiguous_row_selections.push(selections.next().unwrap().clone());
22934        } else {
22935            break;
22936        }
22937    }
22938    (start_row, end_row)
22939}
22940
22941fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22942    if selection.start.column > 0 {
22943        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22944    } else {
22945        MultiBufferRow(selection.start.row)
22946    }
22947}
22948
22949fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22950    if next_selection.end.column > 0 || next_selection.is_empty() {
22951        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22952    } else {
22953        MultiBufferRow(next_selection.end.row)
22954    }
22955}
22956
22957impl EditorSnapshot {
22958    pub fn remote_selections_in_range<'a>(
22959        &'a self,
22960        range: &'a Range<Anchor>,
22961        collaboration_hub: &dyn CollaborationHub,
22962        cx: &'a App,
22963    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22964        let participant_names = collaboration_hub.user_names(cx);
22965        let participant_indices = collaboration_hub.user_participant_indices(cx);
22966        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22967        let collaborators_by_replica_id = collaborators_by_peer_id
22968            .values()
22969            .map(|collaborator| (collaborator.replica_id, collaborator))
22970            .collect::<HashMap<_, _>>();
22971        self.buffer_snapshot
22972            .selections_in_range(range, false)
22973            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22974                if replica_id == AGENT_REPLICA_ID {
22975                    Some(RemoteSelection {
22976                        replica_id,
22977                        selection,
22978                        cursor_shape,
22979                        line_mode,
22980                        collaborator_id: CollaboratorId::Agent,
22981                        user_name: Some("Agent".into()),
22982                        color: cx.theme().players().agent(),
22983                    })
22984                } else {
22985                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22986                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22987                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22988                    Some(RemoteSelection {
22989                        replica_id,
22990                        selection,
22991                        cursor_shape,
22992                        line_mode,
22993                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22994                        user_name,
22995                        color: if let Some(index) = participant_index {
22996                            cx.theme().players().color_for_participant(index.0)
22997                        } else {
22998                            cx.theme().players().absent()
22999                        },
23000                    })
23001                }
23002            })
23003    }
23004
23005    pub fn hunks_for_ranges(
23006        &self,
23007        ranges: impl IntoIterator<Item = Range<Point>>,
23008    ) -> Vec<MultiBufferDiffHunk> {
23009        let mut hunks = Vec::new();
23010        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23011            HashMap::default();
23012        for query_range in ranges {
23013            let query_rows =
23014                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23015            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23016                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23017            ) {
23018                // Include deleted hunks that are adjacent to the query range, because
23019                // otherwise they would be missed.
23020                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23021                if hunk.status().is_deleted() {
23022                    intersects_range |= hunk.row_range.start == query_rows.end;
23023                    intersects_range |= hunk.row_range.end == query_rows.start;
23024                }
23025                if intersects_range {
23026                    if !processed_buffer_rows
23027                        .entry(hunk.buffer_id)
23028                        .or_default()
23029                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23030                    {
23031                        continue;
23032                    }
23033                    hunks.push(hunk);
23034                }
23035            }
23036        }
23037
23038        hunks
23039    }
23040
23041    fn display_diff_hunks_for_rows<'a>(
23042        &'a self,
23043        display_rows: Range<DisplayRow>,
23044        folded_buffers: &'a HashSet<BufferId>,
23045    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23046        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23047        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23048
23049        self.buffer_snapshot
23050            .diff_hunks_in_range(buffer_start..buffer_end)
23051            .filter_map(|hunk| {
23052                if folded_buffers.contains(&hunk.buffer_id) {
23053                    return None;
23054                }
23055
23056                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23057                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23058
23059                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23060                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23061
23062                let display_hunk = if hunk_display_start.column() != 0 {
23063                    DisplayDiffHunk::Folded {
23064                        display_row: hunk_display_start.row(),
23065                    }
23066                } else {
23067                    let mut end_row = hunk_display_end.row();
23068                    if hunk_display_end.column() > 0 {
23069                        end_row.0 += 1;
23070                    }
23071                    let is_created_file = hunk.is_created_file();
23072                    DisplayDiffHunk::Unfolded {
23073                        status: hunk.status(),
23074                        diff_base_byte_range: hunk.diff_base_byte_range,
23075                        display_row_range: hunk_display_start.row()..end_row,
23076                        multi_buffer_range: Anchor::range_in_buffer(
23077                            hunk.excerpt_id,
23078                            hunk.buffer_id,
23079                            hunk.buffer_range,
23080                        ),
23081                        is_created_file,
23082                    }
23083                };
23084
23085                Some(display_hunk)
23086            })
23087    }
23088
23089    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23090        self.display_snapshot.buffer_snapshot.language_at(position)
23091    }
23092
23093    pub fn is_focused(&self) -> bool {
23094        self.is_focused
23095    }
23096
23097    pub fn placeholder_text(&self) -> Option<String> {
23098        self.placeholder_display_snapshot
23099            .as_ref()
23100            .map(|display_map| display_map.text())
23101    }
23102
23103    pub fn scroll_position(&self) -> gpui::Point<f32> {
23104        self.scroll_anchor.scroll_position(&self.display_snapshot)
23105    }
23106
23107    fn gutter_dimensions(
23108        &self,
23109        font_id: FontId,
23110        font_size: Pixels,
23111        max_line_number_width: Pixels,
23112        cx: &App,
23113    ) -> Option<GutterDimensions> {
23114        if !self.show_gutter {
23115            return None;
23116        }
23117
23118        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23119        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23120
23121        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23122            matches!(
23123                ProjectSettings::get_global(cx).git.git_gutter,
23124                GitGutterSetting::TrackedFiles
23125            )
23126        });
23127        let gutter_settings = EditorSettings::get_global(cx).gutter;
23128        let show_line_numbers = self
23129            .show_line_numbers
23130            .unwrap_or(gutter_settings.line_numbers);
23131        let line_gutter_width = if show_line_numbers {
23132            // Avoid flicker-like gutter resizes when the line number gains another digit by
23133            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23134            let min_width_for_number_on_gutter =
23135                ch_advance * gutter_settings.min_line_number_digits as f32;
23136            max_line_number_width.max(min_width_for_number_on_gutter)
23137        } else {
23138            0.0.into()
23139        };
23140
23141        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23142        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23143
23144        let git_blame_entries_width =
23145            self.git_blame_gutter_max_author_length
23146                .map(|max_author_length| {
23147                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23148                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23149
23150                    /// The number of characters to dedicate to gaps and margins.
23151                    const SPACING_WIDTH: usize = 4;
23152
23153                    let max_char_count = max_author_length.min(renderer.max_author_length())
23154                        + ::git::SHORT_SHA_LENGTH
23155                        + MAX_RELATIVE_TIMESTAMP.len()
23156                        + SPACING_WIDTH;
23157
23158                    ch_advance * max_char_count
23159                });
23160
23161        let is_singleton = self.buffer_snapshot.is_singleton();
23162
23163        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23164        left_padding += if !is_singleton {
23165            ch_width * 4.0
23166        } else if show_runnables || show_breakpoints {
23167            ch_width * 3.0
23168        } else if show_git_gutter && show_line_numbers {
23169            ch_width * 2.0
23170        } else if show_git_gutter || show_line_numbers {
23171            ch_width
23172        } else {
23173            px(0.)
23174        };
23175
23176        let shows_folds = is_singleton && gutter_settings.folds;
23177
23178        let right_padding = if shows_folds && show_line_numbers {
23179            ch_width * 4.0
23180        } else if shows_folds || (!is_singleton && show_line_numbers) {
23181            ch_width * 3.0
23182        } else if show_line_numbers {
23183            ch_width
23184        } else {
23185            px(0.)
23186        };
23187
23188        Some(GutterDimensions {
23189            left_padding,
23190            right_padding,
23191            width: line_gutter_width + left_padding + right_padding,
23192            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23193            git_blame_entries_width,
23194        })
23195    }
23196
23197    pub fn render_crease_toggle(
23198        &self,
23199        buffer_row: MultiBufferRow,
23200        row_contains_cursor: bool,
23201        editor: Entity<Editor>,
23202        window: &mut Window,
23203        cx: &mut App,
23204    ) -> Option<AnyElement> {
23205        let folded = self.is_line_folded(buffer_row);
23206        let mut is_foldable = false;
23207
23208        if let Some(crease) = self
23209            .crease_snapshot
23210            .query_row(buffer_row, &self.buffer_snapshot)
23211        {
23212            is_foldable = true;
23213            match crease {
23214                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23215                    if let Some(render_toggle) = render_toggle {
23216                        let toggle_callback =
23217                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23218                                if folded {
23219                                    editor.update(cx, |editor, cx| {
23220                                        editor.fold_at(buffer_row, window, cx)
23221                                    });
23222                                } else {
23223                                    editor.update(cx, |editor, cx| {
23224                                        editor.unfold_at(buffer_row, window, cx)
23225                                    });
23226                                }
23227                            });
23228                        return Some((render_toggle)(
23229                            buffer_row,
23230                            folded,
23231                            toggle_callback,
23232                            window,
23233                            cx,
23234                        ));
23235                    }
23236                }
23237            }
23238        }
23239
23240        is_foldable |= self.starts_indent(buffer_row);
23241
23242        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23243            Some(
23244                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23245                    .toggle_state(folded)
23246                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23247                        if folded {
23248                            this.unfold_at(buffer_row, window, cx);
23249                        } else {
23250                            this.fold_at(buffer_row, window, cx);
23251                        }
23252                    }))
23253                    .into_any_element(),
23254            )
23255        } else {
23256            None
23257        }
23258    }
23259
23260    pub fn render_crease_trailer(
23261        &self,
23262        buffer_row: MultiBufferRow,
23263        window: &mut Window,
23264        cx: &mut App,
23265    ) -> Option<AnyElement> {
23266        let folded = self.is_line_folded(buffer_row);
23267        if let Crease::Inline { render_trailer, .. } = self
23268            .crease_snapshot
23269            .query_row(buffer_row, &self.buffer_snapshot)?
23270        {
23271            let render_trailer = render_trailer.as_ref()?;
23272            Some(render_trailer(buffer_row, folded, window, cx))
23273        } else {
23274            None
23275        }
23276    }
23277}
23278
23279impl Deref for EditorSnapshot {
23280    type Target = DisplaySnapshot;
23281
23282    fn deref(&self) -> &Self::Target {
23283        &self.display_snapshot
23284    }
23285}
23286
23287#[derive(Clone, Debug, PartialEq, Eq)]
23288pub enum EditorEvent {
23289    InputIgnored {
23290        text: Arc<str>,
23291    },
23292    InputHandled {
23293        utf16_range_to_replace: Option<Range<isize>>,
23294        text: Arc<str>,
23295    },
23296    ExcerptsAdded {
23297        buffer: Entity<Buffer>,
23298        predecessor: ExcerptId,
23299        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23300    },
23301    ExcerptsRemoved {
23302        ids: Vec<ExcerptId>,
23303        removed_buffer_ids: Vec<BufferId>,
23304    },
23305    BufferFoldToggled {
23306        ids: Vec<ExcerptId>,
23307        folded: bool,
23308    },
23309    ExcerptsEdited {
23310        ids: Vec<ExcerptId>,
23311    },
23312    ExcerptsExpanded {
23313        ids: Vec<ExcerptId>,
23314    },
23315    BufferEdited,
23316    Edited {
23317        transaction_id: clock::Lamport,
23318    },
23319    Reparsed(BufferId),
23320    Focused,
23321    FocusedIn,
23322    Blurred,
23323    DirtyChanged,
23324    Saved,
23325    TitleChanged,
23326    SelectionsChanged {
23327        local: bool,
23328    },
23329    ScrollPositionChanged {
23330        local: bool,
23331        autoscroll: bool,
23332    },
23333    TransactionUndone {
23334        transaction_id: clock::Lamport,
23335    },
23336    TransactionBegun {
23337        transaction_id: clock::Lamport,
23338    },
23339    CursorShapeChanged,
23340    BreadcrumbsChanged,
23341    PushedToNavHistory {
23342        anchor: Anchor,
23343        is_deactivate: bool,
23344    },
23345}
23346
23347impl EventEmitter<EditorEvent> for Editor {}
23348
23349impl Focusable for Editor {
23350    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23351        self.focus_handle.clone()
23352    }
23353}
23354
23355impl Render for Editor {
23356    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23357        let settings = ThemeSettings::get_global(cx);
23358
23359        let mut text_style = match self.mode {
23360            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23361                color: cx.theme().colors().editor_foreground,
23362                font_family: settings.ui_font.family.clone(),
23363                font_features: settings.ui_font.features.clone(),
23364                font_fallbacks: settings.ui_font.fallbacks.clone(),
23365                font_size: rems(0.875).into(),
23366                font_weight: settings.ui_font.weight,
23367                line_height: relative(settings.buffer_line_height.value()),
23368                ..Default::default()
23369            },
23370            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23371                color: cx.theme().colors().editor_foreground,
23372                font_family: settings.buffer_font.family.clone(),
23373                font_features: settings.buffer_font.features.clone(),
23374                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23375                font_size: settings.buffer_font_size(cx).into(),
23376                font_weight: settings.buffer_font.weight,
23377                line_height: relative(settings.buffer_line_height.value()),
23378                ..Default::default()
23379            },
23380        };
23381        if let Some(text_style_refinement) = &self.text_style_refinement {
23382            text_style.refine(text_style_refinement)
23383        }
23384
23385        let background = match self.mode {
23386            EditorMode::SingleLine => cx.theme().system().transparent,
23387            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23388            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23389            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23390        };
23391
23392        EditorElement::new(
23393            &cx.entity(),
23394            EditorStyle {
23395                background,
23396                border: cx.theme().colors().border,
23397                local_player: cx.theme().players().local(),
23398                text: text_style,
23399                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23400                syntax: cx.theme().syntax().clone(),
23401                status: cx.theme().status().clone(),
23402                inlay_hints_style: make_inlay_hints_style(cx),
23403                edit_prediction_styles: make_suggestion_styles(cx),
23404                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23405                show_underlines: self.diagnostics_enabled(),
23406            },
23407        )
23408    }
23409}
23410
23411impl EntityInputHandler for Editor {
23412    fn text_for_range(
23413        &mut self,
23414        range_utf16: Range<usize>,
23415        adjusted_range: &mut Option<Range<usize>>,
23416        _: &mut Window,
23417        cx: &mut Context<Self>,
23418    ) -> Option<String> {
23419        let snapshot = self.buffer.read(cx).read(cx);
23420        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23421        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23422        if (start.0..end.0) != range_utf16 {
23423            adjusted_range.replace(start.0..end.0);
23424        }
23425        Some(snapshot.text_for_range(start..end).collect())
23426    }
23427
23428    fn selected_text_range(
23429        &mut self,
23430        ignore_disabled_input: bool,
23431        _: &mut Window,
23432        cx: &mut Context<Self>,
23433    ) -> Option<UTF16Selection> {
23434        // Prevent the IME menu from appearing when holding down an alphabetic key
23435        // while input is disabled.
23436        if !ignore_disabled_input && !self.input_enabled {
23437            return None;
23438        }
23439
23440        let selection = self.selections.newest::<OffsetUtf16>(cx);
23441        let range = selection.range();
23442
23443        Some(UTF16Selection {
23444            range: range.start.0..range.end.0,
23445            reversed: selection.reversed,
23446        })
23447    }
23448
23449    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23450        let snapshot = self.buffer.read(cx).read(cx);
23451        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23452        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23453    }
23454
23455    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23456        self.clear_highlights::<InputComposition>(cx);
23457        self.ime_transaction.take();
23458    }
23459
23460    fn replace_text_in_range(
23461        &mut self,
23462        range_utf16: Option<Range<usize>>,
23463        text: &str,
23464        window: &mut Window,
23465        cx: &mut Context<Self>,
23466    ) {
23467        if !self.input_enabled {
23468            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23469            return;
23470        }
23471
23472        self.transact(window, cx, |this, window, cx| {
23473            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23474                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23475                Some(this.selection_replacement_ranges(range_utf16, cx))
23476            } else {
23477                this.marked_text_ranges(cx)
23478            };
23479
23480            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23481                let newest_selection_id = this.selections.newest_anchor().id;
23482                this.selections
23483                    .all::<OffsetUtf16>(cx)
23484                    .iter()
23485                    .zip(ranges_to_replace.iter())
23486                    .find_map(|(selection, range)| {
23487                        if selection.id == newest_selection_id {
23488                            Some(
23489                                (range.start.0 as isize - selection.head().0 as isize)
23490                                    ..(range.end.0 as isize - selection.head().0 as isize),
23491                            )
23492                        } else {
23493                            None
23494                        }
23495                    })
23496            });
23497
23498            cx.emit(EditorEvent::InputHandled {
23499                utf16_range_to_replace: range_to_replace,
23500                text: text.into(),
23501            });
23502
23503            if let Some(new_selected_ranges) = new_selected_ranges {
23504                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23505                    selections.select_ranges(new_selected_ranges)
23506                });
23507                this.backspace(&Default::default(), window, cx);
23508            }
23509
23510            this.handle_input(text, window, cx);
23511        });
23512
23513        if let Some(transaction) = self.ime_transaction {
23514            self.buffer.update(cx, |buffer, cx| {
23515                buffer.group_until_transaction(transaction, cx);
23516            });
23517        }
23518
23519        self.unmark_text(window, cx);
23520    }
23521
23522    fn replace_and_mark_text_in_range(
23523        &mut self,
23524        range_utf16: Option<Range<usize>>,
23525        text: &str,
23526        new_selected_range_utf16: Option<Range<usize>>,
23527        window: &mut Window,
23528        cx: &mut Context<Self>,
23529    ) {
23530        if !self.input_enabled {
23531            return;
23532        }
23533
23534        let transaction = self.transact(window, cx, |this, window, cx| {
23535            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23536                let snapshot = this.buffer.read(cx).read(cx);
23537                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23538                    for marked_range in &mut marked_ranges {
23539                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23540                        marked_range.start.0 += relative_range_utf16.start;
23541                        marked_range.start =
23542                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23543                        marked_range.end =
23544                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23545                    }
23546                }
23547                Some(marked_ranges)
23548            } else if let Some(range_utf16) = range_utf16 {
23549                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23550                Some(this.selection_replacement_ranges(range_utf16, cx))
23551            } else {
23552                None
23553            };
23554
23555            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23556                let newest_selection_id = this.selections.newest_anchor().id;
23557                this.selections
23558                    .all::<OffsetUtf16>(cx)
23559                    .iter()
23560                    .zip(ranges_to_replace.iter())
23561                    .find_map(|(selection, range)| {
23562                        if selection.id == newest_selection_id {
23563                            Some(
23564                                (range.start.0 as isize - selection.head().0 as isize)
23565                                    ..(range.end.0 as isize - selection.head().0 as isize),
23566                            )
23567                        } else {
23568                            None
23569                        }
23570                    })
23571            });
23572
23573            cx.emit(EditorEvent::InputHandled {
23574                utf16_range_to_replace: range_to_replace,
23575                text: text.into(),
23576            });
23577
23578            if let Some(ranges) = ranges_to_replace {
23579                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23580                    s.select_ranges(ranges)
23581                });
23582            }
23583
23584            let marked_ranges = {
23585                let snapshot = this.buffer.read(cx).read(cx);
23586                this.selections
23587                    .disjoint_anchors_arc()
23588                    .iter()
23589                    .map(|selection| {
23590                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23591                    })
23592                    .collect::<Vec<_>>()
23593            };
23594
23595            if text.is_empty() {
23596                this.unmark_text(window, cx);
23597            } else {
23598                this.highlight_text::<InputComposition>(
23599                    marked_ranges.clone(),
23600                    HighlightStyle {
23601                        underline: Some(UnderlineStyle {
23602                            thickness: px(1.),
23603                            color: None,
23604                            wavy: false,
23605                        }),
23606                        ..Default::default()
23607                    },
23608                    cx,
23609                );
23610            }
23611
23612            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23613            let use_autoclose = this.use_autoclose;
23614            let use_auto_surround = this.use_auto_surround;
23615            this.set_use_autoclose(false);
23616            this.set_use_auto_surround(false);
23617            this.handle_input(text, window, cx);
23618            this.set_use_autoclose(use_autoclose);
23619            this.set_use_auto_surround(use_auto_surround);
23620
23621            if let Some(new_selected_range) = new_selected_range_utf16 {
23622                let snapshot = this.buffer.read(cx).read(cx);
23623                let new_selected_ranges = marked_ranges
23624                    .into_iter()
23625                    .map(|marked_range| {
23626                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23627                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23628                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23629                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23630                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23631                    })
23632                    .collect::<Vec<_>>();
23633
23634                drop(snapshot);
23635                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23636                    selections.select_ranges(new_selected_ranges)
23637                });
23638            }
23639        });
23640
23641        self.ime_transaction = self.ime_transaction.or(transaction);
23642        if let Some(transaction) = self.ime_transaction {
23643            self.buffer.update(cx, |buffer, cx| {
23644                buffer.group_until_transaction(transaction, cx);
23645            });
23646        }
23647
23648        if self.text_highlights::<InputComposition>(cx).is_none() {
23649            self.ime_transaction.take();
23650        }
23651    }
23652
23653    fn bounds_for_range(
23654        &mut self,
23655        range_utf16: Range<usize>,
23656        element_bounds: gpui::Bounds<Pixels>,
23657        window: &mut Window,
23658        cx: &mut Context<Self>,
23659    ) -> Option<gpui::Bounds<Pixels>> {
23660        let text_layout_details = self.text_layout_details(window);
23661        let CharacterDimensions {
23662            em_width,
23663            em_advance,
23664            line_height,
23665        } = self.character_dimensions(window);
23666
23667        let snapshot = self.snapshot(window, cx);
23668        let scroll_position = snapshot.scroll_position();
23669        let scroll_left = scroll_position.x * em_advance;
23670
23671        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23672        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23673            + self.gutter_dimensions.full_width();
23674        let y = line_height * (start.row().as_f32() - scroll_position.y);
23675
23676        Some(Bounds {
23677            origin: element_bounds.origin + point(x, y),
23678            size: size(em_width, line_height),
23679        })
23680    }
23681
23682    fn character_index_for_point(
23683        &mut self,
23684        point: gpui::Point<Pixels>,
23685        _window: &mut Window,
23686        _cx: &mut Context<Self>,
23687    ) -> Option<usize> {
23688        let position_map = self.last_position_map.as_ref()?;
23689        if !position_map.text_hitbox.contains(&point) {
23690            return None;
23691        }
23692        let display_point = position_map.point_for_position(point).previous_valid;
23693        let anchor = position_map
23694            .snapshot
23695            .display_point_to_anchor(display_point, Bias::Left);
23696        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23697        Some(utf16_offset.0)
23698    }
23699}
23700
23701trait SelectionExt {
23702    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23703    fn spanned_rows(
23704        &self,
23705        include_end_if_at_line_start: bool,
23706        map: &DisplaySnapshot,
23707    ) -> Range<MultiBufferRow>;
23708}
23709
23710impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23711    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23712        let start = self
23713            .start
23714            .to_point(&map.buffer_snapshot)
23715            .to_display_point(map);
23716        let end = self
23717            .end
23718            .to_point(&map.buffer_snapshot)
23719            .to_display_point(map);
23720        if self.reversed {
23721            end..start
23722        } else {
23723            start..end
23724        }
23725    }
23726
23727    fn spanned_rows(
23728        &self,
23729        include_end_if_at_line_start: bool,
23730        map: &DisplaySnapshot,
23731    ) -> Range<MultiBufferRow> {
23732        let start = self.start.to_point(&map.buffer_snapshot);
23733        let mut end = self.end.to_point(&map.buffer_snapshot);
23734        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23735            end.row -= 1;
23736        }
23737
23738        let buffer_start = map.prev_line_boundary(start).0;
23739        let buffer_end = map.next_line_boundary(end).0;
23740        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23741    }
23742}
23743
23744impl<T: InvalidationRegion> InvalidationStack<T> {
23745    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23746    where
23747        S: Clone + ToOffset,
23748    {
23749        while let Some(region) = self.last() {
23750            let all_selections_inside_invalidation_ranges =
23751                if selections.len() == region.ranges().len() {
23752                    selections
23753                        .iter()
23754                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23755                        .all(|(selection, invalidation_range)| {
23756                            let head = selection.head().to_offset(buffer);
23757                            invalidation_range.start <= head && invalidation_range.end >= head
23758                        })
23759                } else {
23760                    false
23761                };
23762
23763            if all_selections_inside_invalidation_ranges {
23764                break;
23765            } else {
23766                self.pop();
23767            }
23768        }
23769    }
23770}
23771
23772impl<T> Default for InvalidationStack<T> {
23773    fn default() -> Self {
23774        Self(Default::default())
23775    }
23776}
23777
23778impl<T> Deref for InvalidationStack<T> {
23779    type Target = Vec<T>;
23780
23781    fn deref(&self) -> &Self::Target {
23782        &self.0
23783    }
23784}
23785
23786impl<T> DerefMut for InvalidationStack<T> {
23787    fn deref_mut(&mut self) -> &mut Self::Target {
23788        &mut self.0
23789    }
23790}
23791
23792impl InvalidationRegion for SnippetState {
23793    fn ranges(&self) -> &[Range<Anchor>] {
23794        &self.ranges[self.active_index]
23795    }
23796}
23797
23798fn edit_prediction_edit_text(
23799    current_snapshot: &BufferSnapshot,
23800    edits: &[(Range<Anchor>, String)],
23801    edit_preview: &EditPreview,
23802    include_deletions: bool,
23803    cx: &App,
23804) -> HighlightedText {
23805    let edits = edits
23806        .iter()
23807        .map(|(anchor, text)| {
23808            (
23809                anchor.start.text_anchor..anchor.end.text_anchor,
23810                text.clone(),
23811            )
23812        })
23813        .collect::<Vec<_>>();
23814
23815    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23816}
23817
23818fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23819    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23820    // Just show the raw edit text with basic styling
23821    let mut text = String::new();
23822    let mut highlights = Vec::new();
23823
23824    let insertion_highlight_style = HighlightStyle {
23825        color: Some(cx.theme().colors().text),
23826        ..Default::default()
23827    };
23828
23829    for (_, edit_text) in edits {
23830        let start_offset = text.len();
23831        text.push_str(edit_text);
23832        let end_offset = text.len();
23833
23834        if start_offset < end_offset {
23835            highlights.push((start_offset..end_offset, insertion_highlight_style));
23836        }
23837    }
23838
23839    HighlightedText {
23840        text: text.into(),
23841        highlights,
23842    }
23843}
23844
23845pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23846    match severity {
23847        lsp::DiagnosticSeverity::ERROR => colors.error,
23848        lsp::DiagnosticSeverity::WARNING => colors.warning,
23849        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23850        lsp::DiagnosticSeverity::HINT => colors.info,
23851        _ => colors.ignored,
23852    }
23853}
23854
23855pub fn styled_runs_for_code_label<'a>(
23856    label: &'a CodeLabel,
23857    syntax_theme: &'a theme::SyntaxTheme,
23858) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23859    let fade_out = HighlightStyle {
23860        fade_out: Some(0.35),
23861        ..Default::default()
23862    };
23863
23864    let mut prev_end = label.filter_range.end;
23865    label
23866        .runs
23867        .iter()
23868        .enumerate()
23869        .flat_map(move |(ix, (range, highlight_id))| {
23870            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23871                style
23872            } else {
23873                return Default::default();
23874            };
23875            let muted_style = style.highlight(fade_out);
23876
23877            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23878            if range.start >= label.filter_range.end {
23879                if range.start > prev_end {
23880                    runs.push((prev_end..range.start, fade_out));
23881                }
23882                runs.push((range.clone(), muted_style));
23883            } else if range.end <= label.filter_range.end {
23884                runs.push((range.clone(), style));
23885            } else {
23886                runs.push((range.start..label.filter_range.end, style));
23887                runs.push((label.filter_range.end..range.end, muted_style));
23888            }
23889            prev_end = cmp::max(prev_end, range.end);
23890
23891            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23892                runs.push((prev_end..label.text.len(), fade_out));
23893            }
23894
23895            runs
23896        })
23897}
23898
23899pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23900    let mut prev_index = 0;
23901    let mut prev_codepoint: Option<char> = None;
23902    text.char_indices()
23903        .chain([(text.len(), '\0')])
23904        .filter_map(move |(index, codepoint)| {
23905            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23906            let is_boundary = index == text.len()
23907                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23908                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23909            if is_boundary {
23910                let chunk = &text[prev_index..index];
23911                prev_index = index;
23912                Some(chunk)
23913            } else {
23914                None
23915            }
23916        })
23917}
23918
23919pub trait RangeToAnchorExt: Sized {
23920    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23921
23922    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23923        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23924        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23925    }
23926}
23927
23928impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23929    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23930        let start_offset = self.start.to_offset(snapshot);
23931        let end_offset = self.end.to_offset(snapshot);
23932        if start_offset == end_offset {
23933            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23934        } else {
23935            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23936        }
23937    }
23938}
23939
23940pub trait RowExt {
23941    fn as_f32(&self) -> f32;
23942
23943    fn next_row(&self) -> Self;
23944
23945    fn previous_row(&self) -> Self;
23946
23947    fn minus(&self, other: Self) -> u32;
23948}
23949
23950impl RowExt for DisplayRow {
23951    fn as_f32(&self) -> f32 {
23952        self.0 as f32
23953    }
23954
23955    fn next_row(&self) -> Self {
23956        Self(self.0 + 1)
23957    }
23958
23959    fn previous_row(&self) -> Self {
23960        Self(self.0.saturating_sub(1))
23961    }
23962
23963    fn minus(&self, other: Self) -> u32 {
23964        self.0 - other.0
23965    }
23966}
23967
23968impl RowExt for MultiBufferRow {
23969    fn as_f32(&self) -> f32 {
23970        self.0 as f32
23971    }
23972
23973    fn next_row(&self) -> Self {
23974        Self(self.0 + 1)
23975    }
23976
23977    fn previous_row(&self) -> Self {
23978        Self(self.0.saturating_sub(1))
23979    }
23980
23981    fn minus(&self, other: Self) -> u32 {
23982        self.0 - other.0
23983    }
23984}
23985
23986trait RowRangeExt {
23987    type Row;
23988
23989    fn len(&self) -> usize;
23990
23991    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23992}
23993
23994impl RowRangeExt for Range<MultiBufferRow> {
23995    type Row = MultiBufferRow;
23996
23997    fn len(&self) -> usize {
23998        (self.end.0 - self.start.0) as usize
23999    }
24000
24001    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24002        (self.start.0..self.end.0).map(MultiBufferRow)
24003    }
24004}
24005
24006impl RowRangeExt for Range<DisplayRow> {
24007    type Row = DisplayRow;
24008
24009    fn len(&self) -> usize {
24010        (self.end.0 - self.start.0) as usize
24011    }
24012
24013    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24014        (self.start.0..self.end.0).map(DisplayRow)
24015    }
24016}
24017
24018/// If select range has more than one line, we
24019/// just point the cursor to range.start.
24020fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24021    if range.start.row == range.end.row {
24022        range
24023    } else {
24024        range.start..range.start
24025    }
24026}
24027pub struct KillRing(ClipboardItem);
24028impl Global for KillRing {}
24029
24030const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24031
24032enum BreakpointPromptEditAction {
24033    Log,
24034    Condition,
24035    HitCondition,
24036}
24037
24038struct BreakpointPromptEditor {
24039    pub(crate) prompt: Entity<Editor>,
24040    editor: WeakEntity<Editor>,
24041    breakpoint_anchor: Anchor,
24042    breakpoint: Breakpoint,
24043    edit_action: BreakpointPromptEditAction,
24044    block_ids: HashSet<CustomBlockId>,
24045    editor_margins: Arc<Mutex<EditorMargins>>,
24046    _subscriptions: Vec<Subscription>,
24047}
24048
24049impl BreakpointPromptEditor {
24050    const MAX_LINES: u8 = 4;
24051
24052    fn new(
24053        editor: WeakEntity<Editor>,
24054        breakpoint_anchor: Anchor,
24055        breakpoint: Breakpoint,
24056        edit_action: BreakpointPromptEditAction,
24057        window: &mut Window,
24058        cx: &mut Context<Self>,
24059    ) -> Self {
24060        let base_text = match edit_action {
24061            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24062            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24063            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24064        }
24065        .map(|msg| msg.to_string())
24066        .unwrap_or_default();
24067
24068        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24069        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24070
24071        let prompt = cx.new(|cx| {
24072            let mut prompt = Editor::new(
24073                EditorMode::AutoHeight {
24074                    min_lines: 1,
24075                    max_lines: Some(Self::MAX_LINES as usize),
24076                },
24077                buffer,
24078                None,
24079                window,
24080                cx,
24081            );
24082            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24083            prompt.set_show_cursor_when_unfocused(false, cx);
24084            prompt.set_placeholder_text(
24085                match edit_action {
24086                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24087                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24088                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24089                },
24090                window,
24091                cx,
24092            );
24093
24094            prompt
24095        });
24096
24097        Self {
24098            prompt,
24099            editor,
24100            breakpoint_anchor,
24101            breakpoint,
24102            edit_action,
24103            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24104            block_ids: Default::default(),
24105            _subscriptions: vec![],
24106        }
24107    }
24108
24109    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24110        self.block_ids.extend(block_ids)
24111    }
24112
24113    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24114        if let Some(editor) = self.editor.upgrade() {
24115            let message = self
24116                .prompt
24117                .read(cx)
24118                .buffer
24119                .read(cx)
24120                .as_singleton()
24121                .expect("A multi buffer in breakpoint prompt isn't possible")
24122                .read(cx)
24123                .as_rope()
24124                .to_string();
24125
24126            editor.update(cx, |editor, cx| {
24127                editor.edit_breakpoint_at_anchor(
24128                    self.breakpoint_anchor,
24129                    self.breakpoint.clone(),
24130                    match self.edit_action {
24131                        BreakpointPromptEditAction::Log => {
24132                            BreakpointEditAction::EditLogMessage(message.into())
24133                        }
24134                        BreakpointPromptEditAction::Condition => {
24135                            BreakpointEditAction::EditCondition(message.into())
24136                        }
24137                        BreakpointPromptEditAction::HitCondition => {
24138                            BreakpointEditAction::EditHitCondition(message.into())
24139                        }
24140                    },
24141                    cx,
24142                );
24143
24144                editor.remove_blocks(self.block_ids.clone(), None, cx);
24145                cx.focus_self(window);
24146            });
24147        }
24148    }
24149
24150    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24151        self.editor
24152            .update(cx, |editor, cx| {
24153                editor.remove_blocks(self.block_ids.clone(), None, cx);
24154                window.focus(&editor.focus_handle);
24155            })
24156            .log_err();
24157    }
24158
24159    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24160        let settings = ThemeSettings::get_global(cx);
24161        let text_style = TextStyle {
24162            color: if self.prompt.read(cx).read_only(cx) {
24163                cx.theme().colors().text_disabled
24164            } else {
24165                cx.theme().colors().text
24166            },
24167            font_family: settings.buffer_font.family.clone(),
24168            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24169            font_size: settings.buffer_font_size(cx).into(),
24170            font_weight: settings.buffer_font.weight,
24171            line_height: relative(settings.buffer_line_height.value()),
24172            ..Default::default()
24173        };
24174        EditorElement::new(
24175            &self.prompt,
24176            EditorStyle {
24177                background: cx.theme().colors().editor_background,
24178                local_player: cx.theme().players().local(),
24179                text: text_style,
24180                ..Default::default()
24181            },
24182        )
24183    }
24184}
24185
24186impl Render for BreakpointPromptEditor {
24187    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24188        let editor_margins = *self.editor_margins.lock();
24189        let gutter_dimensions = editor_margins.gutter;
24190        h_flex()
24191            .key_context("Editor")
24192            .bg(cx.theme().colors().editor_background)
24193            .border_y_1()
24194            .border_color(cx.theme().status().info_border)
24195            .size_full()
24196            .py(window.line_height() / 2.5)
24197            .on_action(cx.listener(Self::confirm))
24198            .on_action(cx.listener(Self::cancel))
24199            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24200            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24201    }
24202}
24203
24204impl Focusable for BreakpointPromptEditor {
24205    fn focus_handle(&self, cx: &App) -> FocusHandle {
24206        self.prompt.focus_handle(cx)
24207    }
24208}
24209
24210fn all_edits_insertions_or_deletions(
24211    edits: &Vec<(Range<Anchor>, String)>,
24212    snapshot: &MultiBufferSnapshot,
24213) -> bool {
24214    let mut all_insertions = true;
24215    let mut all_deletions = true;
24216
24217    for (range, new_text) in edits.iter() {
24218        let range_is_empty = range.to_offset(snapshot).is_empty();
24219        let text_is_empty = new_text.is_empty();
24220
24221        if range_is_empty != text_is_empty {
24222            if range_is_empty {
24223                all_deletions = false;
24224            } else {
24225                all_insertions = false;
24226            }
24227        } else {
24228            return false;
24229        }
24230
24231        if !all_insertions && !all_deletions {
24232            return false;
24233        }
24234    }
24235    all_insertions || all_deletions
24236}
24237
24238struct MissingEditPredictionKeybindingTooltip;
24239
24240impl Render for MissingEditPredictionKeybindingTooltip {
24241    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24242        ui::tooltip_container(window, cx, |container, _, cx| {
24243            container
24244                .flex_shrink_0()
24245                .max_w_80()
24246                .min_h(rems_from_px(124.))
24247                .justify_between()
24248                .child(
24249                    v_flex()
24250                        .flex_1()
24251                        .text_ui_sm(cx)
24252                        .child(Label::new("Conflict with Accept Keybinding"))
24253                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24254                )
24255                .child(
24256                    h_flex()
24257                        .pb_1()
24258                        .gap_1()
24259                        .items_end()
24260                        .w_full()
24261                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24262                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24263                        }))
24264                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24265                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24266                        })),
24267                )
24268        })
24269    }
24270}
24271
24272#[derive(Debug, Clone, Copy, PartialEq)]
24273pub struct LineHighlight {
24274    pub background: Background,
24275    pub border: Option<gpui::Hsla>,
24276    pub include_gutter: bool,
24277    pub type_id: Option<TypeId>,
24278}
24279
24280struct LineManipulationResult {
24281    pub new_text: String,
24282    pub line_count_before: usize,
24283    pub line_count_after: usize,
24284}
24285
24286fn render_diff_hunk_controls(
24287    row: u32,
24288    status: &DiffHunkStatus,
24289    hunk_range: Range<Anchor>,
24290    is_created_file: bool,
24291    line_height: Pixels,
24292    editor: &Entity<Editor>,
24293    _window: &mut Window,
24294    cx: &mut App,
24295) -> AnyElement {
24296    h_flex()
24297        .h(line_height)
24298        .mr_1()
24299        .gap_1()
24300        .px_0p5()
24301        .pb_1()
24302        .border_x_1()
24303        .border_b_1()
24304        .border_color(cx.theme().colors().border_variant)
24305        .rounded_b_lg()
24306        .bg(cx.theme().colors().editor_background)
24307        .gap_1()
24308        .block_mouse_except_scroll()
24309        .shadow_md()
24310        .child(if status.has_secondary_hunk() {
24311            Button::new(("stage", row as u64), "Stage")
24312                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24313                .tooltip({
24314                    let focus_handle = editor.focus_handle(cx);
24315                    move |window, cx| {
24316                        Tooltip::for_action_in(
24317                            "Stage Hunk",
24318                            &::git::ToggleStaged,
24319                            &focus_handle,
24320                            window,
24321                            cx,
24322                        )
24323                    }
24324                })
24325                .on_click({
24326                    let editor = editor.clone();
24327                    move |_event, _window, cx| {
24328                        editor.update(cx, |editor, cx| {
24329                            editor.stage_or_unstage_diff_hunks(
24330                                true,
24331                                vec![hunk_range.start..hunk_range.start],
24332                                cx,
24333                            );
24334                        });
24335                    }
24336                })
24337        } else {
24338            Button::new(("unstage", row as u64), "Unstage")
24339                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24340                .tooltip({
24341                    let focus_handle = editor.focus_handle(cx);
24342                    move |window, cx| {
24343                        Tooltip::for_action_in(
24344                            "Unstage Hunk",
24345                            &::git::ToggleStaged,
24346                            &focus_handle,
24347                            window,
24348                            cx,
24349                        )
24350                    }
24351                })
24352                .on_click({
24353                    let editor = editor.clone();
24354                    move |_event, _window, cx| {
24355                        editor.update(cx, |editor, cx| {
24356                            editor.stage_or_unstage_diff_hunks(
24357                                false,
24358                                vec![hunk_range.start..hunk_range.start],
24359                                cx,
24360                            );
24361                        });
24362                    }
24363                })
24364        })
24365        .child(
24366            Button::new(("restore", row as u64), "Restore")
24367                .tooltip({
24368                    let focus_handle = editor.focus_handle(cx);
24369                    move |window, cx| {
24370                        Tooltip::for_action_in(
24371                            "Restore Hunk",
24372                            &::git::Restore,
24373                            &focus_handle,
24374                            window,
24375                            cx,
24376                        )
24377                    }
24378                })
24379                .on_click({
24380                    let editor = editor.clone();
24381                    move |_event, window, cx| {
24382                        editor.update(cx, |editor, cx| {
24383                            let snapshot = editor.snapshot(window, cx);
24384                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24385                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24386                        });
24387                    }
24388                })
24389                .disabled(is_created_file),
24390        )
24391        .when(
24392            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24393            |el| {
24394                el.child(
24395                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24396                        .shape(IconButtonShape::Square)
24397                        .icon_size(IconSize::Small)
24398                        // .disabled(!has_multiple_hunks)
24399                        .tooltip({
24400                            let focus_handle = editor.focus_handle(cx);
24401                            move |window, cx| {
24402                                Tooltip::for_action_in(
24403                                    "Next Hunk",
24404                                    &GoToHunk,
24405                                    &focus_handle,
24406                                    window,
24407                                    cx,
24408                                )
24409                            }
24410                        })
24411                        .on_click({
24412                            let editor = editor.clone();
24413                            move |_event, window, cx| {
24414                                editor.update(cx, |editor, cx| {
24415                                    let snapshot = editor.snapshot(window, cx);
24416                                    let position =
24417                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24418                                    editor.go_to_hunk_before_or_after_position(
24419                                        &snapshot,
24420                                        position,
24421                                        Direction::Next,
24422                                        window,
24423                                        cx,
24424                                    );
24425                                    editor.expand_selected_diff_hunks(cx);
24426                                });
24427                            }
24428                        }),
24429                )
24430                .child(
24431                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24432                        .shape(IconButtonShape::Square)
24433                        .icon_size(IconSize::Small)
24434                        // .disabled(!has_multiple_hunks)
24435                        .tooltip({
24436                            let focus_handle = editor.focus_handle(cx);
24437                            move |window, cx| {
24438                                Tooltip::for_action_in(
24439                                    "Previous Hunk",
24440                                    &GoToPreviousHunk,
24441                                    &focus_handle,
24442                                    window,
24443                                    cx,
24444                                )
24445                            }
24446                        })
24447                        .on_click({
24448                            let editor = editor.clone();
24449                            move |_event, window, cx| {
24450                                editor.update(cx, |editor, cx| {
24451                                    let snapshot = editor.snapshot(window, cx);
24452                                    let point =
24453                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24454                                    editor.go_to_hunk_before_or_after_position(
24455                                        &snapshot,
24456                                        point,
24457                                        Direction::Prev,
24458                                        window,
24459                                        cx,
24460                                    );
24461                                    editor.expand_selected_diff_hunks(cx);
24462                                });
24463                            }
24464                        }),
24465                )
24466            },
24467        )
24468        .into_any_element()
24469}
24470
24471pub fn multibuffer_context_lines(cx: &App) -> u32 {
24472    EditorSettings::try_get(cx)
24473        .map(|settings| settings.excerpt_context_lines)
24474        .unwrap_or(2)
24475        .min(32)
24476}