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, CharScopeContext, CodeLabel, CursorShape,
  125    DiagnosticEntry, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  126    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  127    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  152    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  153    ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  164};
  165use rand::seq::SliceRandom;
  166use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  167use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  168use selections_collection::{
  169    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  170};
  171use serde::{Deserialize, Serialize};
  172use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  173use smallvec::{SmallVec, smallvec};
  174use snippet::Snippet;
  175use std::{
  176    any::{Any, TypeId},
  177    borrow::Cow,
  178    cell::{OnceCell, RefCell},
  179    cmp::{self, Ordering, Reverse},
  180    iter::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, Some(CharScopeContext::Completion))
 3127                            == Some(CharKind::Word)
 3128                    } else {
 3129                        // Snippet choices can be shown even when the cursor is in whitespace.
 3130                        // Dismissing the menu with actions like backspace is handled by
 3131                        // invalidation regions.
 3132                        true
 3133                    }
 3134                } else {
 3135                    false
 3136                };
 3137
 3138                if continue_showing {
 3139                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3140                } else {
 3141                    self.hide_context_menu(window, cx);
 3142                }
 3143            }
 3144
 3145            hide_hover(self, cx);
 3146
 3147            if old_cursor_position.to_display_point(&display_map).row()
 3148                != new_cursor_position.to_display_point(&display_map).row()
 3149            {
 3150                self.available_code_actions.take();
 3151            }
 3152            self.refresh_code_actions(window, cx);
 3153            self.refresh_document_highlights(cx);
 3154            self.refresh_selected_text_highlights(false, window, cx);
 3155            refresh_matching_bracket_highlights(self, window, cx);
 3156            self.update_visible_edit_prediction(window, cx);
 3157            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3158            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3159            self.inline_blame_popover.take();
 3160            if self.git_blame_inline_enabled {
 3161                self.start_inline_blame_timer(window, cx);
 3162            }
 3163        }
 3164
 3165        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3166        cx.emit(EditorEvent::SelectionsChanged { local });
 3167
 3168        let selections = &self.selections.disjoint_anchors_arc();
 3169        if selections.len() == 1 {
 3170            cx.emit(SearchEvent::ActiveMatchChanged)
 3171        }
 3172        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3173            let inmemory_selections = selections
 3174                .iter()
 3175                .map(|s| {
 3176                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3177                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3178                })
 3179                .collect();
 3180            self.update_restoration_data(cx, |data| {
 3181                data.selections = inmemory_selections;
 3182            });
 3183
 3184            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3185                && let Some(workspace_id) =
 3186                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3187            {
 3188                let snapshot = self.buffer().read(cx).snapshot(cx);
 3189                let selections = selections.clone();
 3190                let background_executor = cx.background_executor().clone();
 3191                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3192                self.serialize_selections = cx.background_spawn(async move {
 3193                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3194                            let db_selections = selections
 3195                                .iter()
 3196                                .map(|selection| {
 3197                                    (
 3198                                        selection.start.to_offset(&snapshot),
 3199                                        selection.end.to_offset(&snapshot),
 3200                                    )
 3201                                })
 3202                                .collect();
 3203
 3204                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3205                                .await
 3206                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3207                                .log_err();
 3208                        });
 3209            }
 3210        }
 3211
 3212        cx.notify();
 3213    }
 3214
 3215    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3216        use text::ToOffset as _;
 3217        use text::ToPoint as _;
 3218
 3219        if self.mode.is_minimap()
 3220            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3221        {
 3222            return;
 3223        }
 3224
 3225        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3226            return;
 3227        };
 3228
 3229        let snapshot = singleton.read(cx).snapshot();
 3230        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3231            let display_snapshot = display_map.snapshot(cx);
 3232
 3233            display_snapshot
 3234                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3235                .map(|fold| {
 3236                    fold.range.start.text_anchor.to_point(&snapshot)
 3237                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3238                })
 3239                .collect()
 3240        });
 3241        self.update_restoration_data(cx, |data| {
 3242            data.folds = inmemory_folds;
 3243        });
 3244
 3245        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3246            return;
 3247        };
 3248        let background_executor = cx.background_executor().clone();
 3249        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3250        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3251            display_map
 3252                .snapshot(cx)
 3253                .folds_in_range(0..snapshot.len())
 3254                .map(|fold| {
 3255                    (
 3256                        fold.range.start.text_anchor.to_offset(&snapshot),
 3257                        fold.range.end.text_anchor.to_offset(&snapshot),
 3258                    )
 3259                })
 3260                .collect()
 3261        });
 3262        self.serialize_folds = cx.background_spawn(async move {
 3263            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3264            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3265                .await
 3266                .with_context(|| {
 3267                    format!(
 3268                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3269                    )
 3270                })
 3271                .log_err();
 3272        });
 3273    }
 3274
 3275    pub fn sync_selections(
 3276        &mut self,
 3277        other: Entity<Editor>,
 3278        cx: &mut Context<Self>,
 3279    ) -> gpui::Subscription {
 3280        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3281        self.selections.change_with(cx, |selections| {
 3282            selections.select_anchors(other_selections);
 3283        });
 3284
 3285        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3286            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3287                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3288                if other_selections.is_empty() {
 3289                    return;
 3290                }
 3291                this.selections.change_with(cx, |selections| {
 3292                    selections.select_anchors(other_selections);
 3293                });
 3294            }
 3295        });
 3296
 3297        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3298            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3299                let these_selections = this.selections.disjoint_anchors().to_vec();
 3300                if these_selections.is_empty() {
 3301                    return;
 3302                }
 3303                other.update(cx, |other_editor, cx| {
 3304                    other_editor.selections.change_with(cx, |selections| {
 3305                        selections.select_anchors(these_selections);
 3306                    })
 3307                });
 3308            }
 3309        });
 3310
 3311        Subscription::join(other_subscription, this_subscription)
 3312    }
 3313
 3314    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3315    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3316    /// effects of selection change occur at the end of the transaction.
 3317    pub fn change_selections<R>(
 3318        &mut self,
 3319        effects: SelectionEffects,
 3320        window: &mut Window,
 3321        cx: &mut Context<Self>,
 3322        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3323    ) -> R {
 3324        if let Some(state) = &mut self.deferred_selection_effects_state {
 3325            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3326            state.effects.completions = effects.completions;
 3327            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3328            let (changed, result) = self.selections.change_with(cx, change);
 3329            state.changed |= changed;
 3330            return result;
 3331        }
 3332        let mut state = DeferredSelectionEffectsState {
 3333            changed: false,
 3334            effects,
 3335            old_cursor_position: self.selections.newest_anchor().head(),
 3336            history_entry: SelectionHistoryEntry {
 3337                selections: self.selections.disjoint_anchors_arc(),
 3338                select_next_state: self.select_next_state.clone(),
 3339                select_prev_state: self.select_prev_state.clone(),
 3340                add_selections_state: self.add_selections_state.clone(),
 3341            },
 3342        };
 3343        let (changed, result) = self.selections.change_with(cx, change);
 3344        state.changed = state.changed || changed;
 3345        if self.defer_selection_effects {
 3346            self.deferred_selection_effects_state = Some(state);
 3347        } else {
 3348            self.apply_selection_effects(state, window, cx);
 3349        }
 3350        result
 3351    }
 3352
 3353    /// Defers the effects of selection change, so that the effects of multiple calls to
 3354    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3355    /// to selection history and the state of popovers based on selection position aren't
 3356    /// erroneously updated.
 3357    pub fn with_selection_effects_deferred<R>(
 3358        &mut self,
 3359        window: &mut Window,
 3360        cx: &mut Context<Self>,
 3361        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3362    ) -> R {
 3363        let already_deferred = self.defer_selection_effects;
 3364        self.defer_selection_effects = true;
 3365        let result = update(self, window, cx);
 3366        if !already_deferred {
 3367            self.defer_selection_effects = false;
 3368            if let Some(state) = self.deferred_selection_effects_state.take() {
 3369                self.apply_selection_effects(state, window, cx);
 3370            }
 3371        }
 3372        result
 3373    }
 3374
 3375    fn apply_selection_effects(
 3376        &mut self,
 3377        state: DeferredSelectionEffectsState,
 3378        window: &mut Window,
 3379        cx: &mut Context<Self>,
 3380    ) {
 3381        if state.changed {
 3382            self.selection_history.push(state.history_entry);
 3383
 3384            if let Some(autoscroll) = state.effects.scroll {
 3385                self.request_autoscroll(autoscroll, cx);
 3386            }
 3387
 3388            let old_cursor_position = &state.old_cursor_position;
 3389
 3390            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3391
 3392            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3393                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3394            }
 3395        }
 3396    }
 3397
 3398    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3399    where
 3400        I: IntoIterator<Item = (Range<S>, T)>,
 3401        S: ToOffset,
 3402        T: Into<Arc<str>>,
 3403    {
 3404        if self.read_only(cx) {
 3405            return;
 3406        }
 3407
 3408        self.buffer
 3409            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3410    }
 3411
 3412    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3413    where
 3414        I: IntoIterator<Item = (Range<S>, T)>,
 3415        S: ToOffset,
 3416        T: Into<Arc<str>>,
 3417    {
 3418        if self.read_only(cx) {
 3419            return;
 3420        }
 3421
 3422        self.buffer.update(cx, |buffer, cx| {
 3423            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3424        });
 3425    }
 3426
 3427    pub fn edit_with_block_indent<I, S, T>(
 3428        &mut self,
 3429        edits: I,
 3430        original_indent_columns: Vec<Option<u32>>,
 3431        cx: &mut Context<Self>,
 3432    ) where
 3433        I: IntoIterator<Item = (Range<S>, T)>,
 3434        S: ToOffset,
 3435        T: Into<Arc<str>>,
 3436    {
 3437        if self.read_only(cx) {
 3438            return;
 3439        }
 3440
 3441        self.buffer.update(cx, |buffer, cx| {
 3442            buffer.edit(
 3443                edits,
 3444                Some(AutoindentMode::Block {
 3445                    original_indent_columns,
 3446                }),
 3447                cx,
 3448            )
 3449        });
 3450    }
 3451
 3452    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3453        self.hide_context_menu(window, cx);
 3454
 3455        match phase {
 3456            SelectPhase::Begin {
 3457                position,
 3458                add,
 3459                click_count,
 3460            } => self.begin_selection(position, add, click_count, window, cx),
 3461            SelectPhase::BeginColumnar {
 3462                position,
 3463                goal_column,
 3464                reset,
 3465                mode,
 3466            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3467            SelectPhase::Extend {
 3468                position,
 3469                click_count,
 3470            } => self.extend_selection(position, click_count, window, cx),
 3471            SelectPhase::Update {
 3472                position,
 3473                goal_column,
 3474                scroll_delta,
 3475            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3476            SelectPhase::End => self.end_selection(window, cx),
 3477        }
 3478    }
 3479
 3480    fn extend_selection(
 3481        &mut self,
 3482        position: DisplayPoint,
 3483        click_count: usize,
 3484        window: &mut Window,
 3485        cx: &mut Context<Self>,
 3486    ) {
 3487        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3488        let tail = self.selections.newest::<usize>(cx).tail();
 3489        self.begin_selection(position, false, click_count, window, cx);
 3490
 3491        let position = position.to_offset(&display_map, Bias::Left);
 3492        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3493
 3494        let mut pending_selection = self
 3495            .selections
 3496            .pending_anchor()
 3497            .cloned()
 3498            .expect("extend_selection not called with pending selection");
 3499        if position >= tail {
 3500            pending_selection.start = tail_anchor;
 3501        } else {
 3502            pending_selection.end = tail_anchor;
 3503            pending_selection.reversed = true;
 3504        }
 3505
 3506        let mut pending_mode = self.selections.pending_mode().unwrap();
 3507        match &mut pending_mode {
 3508            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3509            _ => {}
 3510        }
 3511
 3512        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3513            SelectionEffects::scroll(Autoscroll::fit())
 3514        } else {
 3515            SelectionEffects::no_scroll()
 3516        };
 3517
 3518        self.change_selections(effects, window, cx, |s| {
 3519            s.set_pending(pending_selection.clone(), pending_mode)
 3520        });
 3521    }
 3522
 3523    fn begin_selection(
 3524        &mut self,
 3525        position: DisplayPoint,
 3526        add: bool,
 3527        click_count: usize,
 3528        window: &mut Window,
 3529        cx: &mut Context<Self>,
 3530    ) {
 3531        if !self.focus_handle.is_focused(window) {
 3532            self.last_focused_descendant = None;
 3533            window.focus(&self.focus_handle);
 3534        }
 3535
 3536        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3537        let buffer = &display_map.buffer_snapshot;
 3538        let position = display_map.clip_point(position, Bias::Left);
 3539
 3540        let start;
 3541        let end;
 3542        let mode;
 3543        let mut auto_scroll;
 3544        match click_count {
 3545            1 => {
 3546                start = buffer.anchor_before(position.to_point(&display_map));
 3547                end = start;
 3548                mode = SelectMode::Character;
 3549                auto_scroll = true;
 3550            }
 3551            2 => {
 3552                let position = display_map
 3553                    .clip_point(position, Bias::Left)
 3554                    .to_offset(&display_map, Bias::Left);
 3555                let (range, _) = buffer.surrounding_word(position, None);
 3556                start = buffer.anchor_before(range.start);
 3557                end = buffer.anchor_before(range.end);
 3558                mode = SelectMode::Word(start..end);
 3559                auto_scroll = true;
 3560            }
 3561            3 => {
 3562                let position = display_map
 3563                    .clip_point(position, Bias::Left)
 3564                    .to_point(&display_map);
 3565                let line_start = display_map.prev_line_boundary(position).0;
 3566                let next_line_start = buffer.clip_point(
 3567                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3568                    Bias::Left,
 3569                );
 3570                start = buffer.anchor_before(line_start);
 3571                end = buffer.anchor_before(next_line_start);
 3572                mode = SelectMode::Line(start..end);
 3573                auto_scroll = true;
 3574            }
 3575            _ => {
 3576                start = buffer.anchor_before(0);
 3577                end = buffer.anchor_before(buffer.len());
 3578                mode = SelectMode::All;
 3579                auto_scroll = false;
 3580            }
 3581        }
 3582        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3583
 3584        let point_to_delete: Option<usize> = {
 3585            let selected_points: Vec<Selection<Point>> =
 3586                self.selections.disjoint_in_range(start..end, cx);
 3587
 3588            if !add || click_count > 1 {
 3589                None
 3590            } else if !selected_points.is_empty() {
 3591                Some(selected_points[0].id)
 3592            } else {
 3593                let clicked_point_already_selected =
 3594                    self.selections.disjoint_anchors().iter().find(|selection| {
 3595                        selection.start.to_point(buffer) == start.to_point(buffer)
 3596                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3597                    });
 3598
 3599                clicked_point_already_selected.map(|selection| selection.id)
 3600            }
 3601        };
 3602
 3603        let selections_count = self.selections.count();
 3604        let effects = if auto_scroll {
 3605            SelectionEffects::default()
 3606        } else {
 3607            SelectionEffects::no_scroll()
 3608        };
 3609
 3610        self.change_selections(effects, window, cx, |s| {
 3611            if let Some(point_to_delete) = point_to_delete {
 3612                s.delete(point_to_delete);
 3613
 3614                if selections_count == 1 {
 3615                    s.set_pending_anchor_range(start..end, mode);
 3616                }
 3617            } else {
 3618                if !add {
 3619                    s.clear_disjoint();
 3620                }
 3621
 3622                s.set_pending_anchor_range(start..end, mode);
 3623            }
 3624        });
 3625    }
 3626
 3627    fn begin_columnar_selection(
 3628        &mut self,
 3629        position: DisplayPoint,
 3630        goal_column: u32,
 3631        reset: bool,
 3632        mode: ColumnarMode,
 3633        window: &mut Window,
 3634        cx: &mut Context<Self>,
 3635    ) {
 3636        if !self.focus_handle.is_focused(window) {
 3637            self.last_focused_descendant = None;
 3638            window.focus(&self.focus_handle);
 3639        }
 3640
 3641        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3642
 3643        if reset {
 3644            let pointer_position = display_map
 3645                .buffer_snapshot
 3646                .anchor_before(position.to_point(&display_map));
 3647
 3648            self.change_selections(
 3649                SelectionEffects::scroll(Autoscroll::newest()),
 3650                window,
 3651                cx,
 3652                |s| {
 3653                    s.clear_disjoint();
 3654                    s.set_pending_anchor_range(
 3655                        pointer_position..pointer_position,
 3656                        SelectMode::Character,
 3657                    );
 3658                },
 3659            );
 3660        };
 3661
 3662        let tail = self.selections.newest::<Point>(cx).tail();
 3663        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3664        self.columnar_selection_state = match mode {
 3665            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3666                selection_tail: selection_anchor,
 3667                display_point: if reset {
 3668                    if position.column() != goal_column {
 3669                        Some(DisplayPoint::new(position.row(), goal_column))
 3670                    } else {
 3671                        None
 3672                    }
 3673                } else {
 3674                    None
 3675                },
 3676            }),
 3677            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3678                selection_tail: selection_anchor,
 3679            }),
 3680        };
 3681
 3682        if !reset {
 3683            self.select_columns(position, goal_column, &display_map, window, cx);
 3684        }
 3685    }
 3686
 3687    fn update_selection(
 3688        &mut self,
 3689        position: DisplayPoint,
 3690        goal_column: u32,
 3691        scroll_delta: gpui::Point<f32>,
 3692        window: &mut Window,
 3693        cx: &mut Context<Self>,
 3694    ) {
 3695        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3696
 3697        if self.columnar_selection_state.is_some() {
 3698            self.select_columns(position, goal_column, &display_map, window, cx);
 3699        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3700            let buffer = &display_map.buffer_snapshot;
 3701            let head;
 3702            let tail;
 3703            let mode = self.selections.pending_mode().unwrap();
 3704            match &mode {
 3705                SelectMode::Character => {
 3706                    head = position.to_point(&display_map);
 3707                    tail = pending.tail().to_point(buffer);
 3708                }
 3709                SelectMode::Word(original_range) => {
 3710                    let offset = display_map
 3711                        .clip_point(position, Bias::Left)
 3712                        .to_offset(&display_map, Bias::Left);
 3713                    let original_range = original_range.to_offset(buffer);
 3714
 3715                    let head_offset = if buffer.is_inside_word(offset, None)
 3716                        || original_range.contains(&offset)
 3717                    {
 3718                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3719                        if word_range.start < original_range.start {
 3720                            word_range.start
 3721                        } else {
 3722                            word_range.end
 3723                        }
 3724                    } else {
 3725                        offset
 3726                    };
 3727
 3728                    head = head_offset.to_point(buffer);
 3729                    if head_offset <= original_range.start {
 3730                        tail = original_range.end.to_point(buffer);
 3731                    } else {
 3732                        tail = original_range.start.to_point(buffer);
 3733                    }
 3734                }
 3735                SelectMode::Line(original_range) => {
 3736                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3737
 3738                    let position = display_map
 3739                        .clip_point(position, Bias::Left)
 3740                        .to_point(&display_map);
 3741                    let line_start = display_map.prev_line_boundary(position).0;
 3742                    let next_line_start = buffer.clip_point(
 3743                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3744                        Bias::Left,
 3745                    );
 3746
 3747                    if line_start < original_range.start {
 3748                        head = line_start
 3749                    } else {
 3750                        head = next_line_start
 3751                    }
 3752
 3753                    if head <= original_range.start {
 3754                        tail = original_range.end;
 3755                    } else {
 3756                        tail = original_range.start;
 3757                    }
 3758                }
 3759                SelectMode::All => {
 3760                    return;
 3761                }
 3762            };
 3763
 3764            if head < tail {
 3765                pending.start = buffer.anchor_before(head);
 3766                pending.end = buffer.anchor_before(tail);
 3767                pending.reversed = true;
 3768            } else {
 3769                pending.start = buffer.anchor_before(tail);
 3770                pending.end = buffer.anchor_before(head);
 3771                pending.reversed = false;
 3772            }
 3773
 3774            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3775                s.set_pending(pending.clone(), mode);
 3776            });
 3777        } else {
 3778            log::error!("update_selection dispatched with no pending selection");
 3779            return;
 3780        }
 3781
 3782        self.apply_scroll_delta(scroll_delta, window, cx);
 3783        cx.notify();
 3784    }
 3785
 3786    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3787        self.columnar_selection_state.take();
 3788        if self.selections.pending_anchor().is_some() {
 3789            let selections = self.selections.all::<usize>(cx);
 3790            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3791                s.select(selections);
 3792                s.clear_pending();
 3793            });
 3794        }
 3795    }
 3796
 3797    fn select_columns(
 3798        &mut self,
 3799        head: DisplayPoint,
 3800        goal_column: u32,
 3801        display_map: &DisplaySnapshot,
 3802        window: &mut Window,
 3803        cx: &mut Context<Self>,
 3804    ) {
 3805        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3806            return;
 3807        };
 3808
 3809        let tail = match columnar_state {
 3810            ColumnarSelectionState::FromMouse {
 3811                selection_tail,
 3812                display_point,
 3813            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3814            ColumnarSelectionState::FromSelection { selection_tail } => {
 3815                selection_tail.to_display_point(display_map)
 3816            }
 3817        };
 3818
 3819        let start_row = cmp::min(tail.row(), head.row());
 3820        let end_row = cmp::max(tail.row(), head.row());
 3821        let start_column = cmp::min(tail.column(), goal_column);
 3822        let end_column = cmp::max(tail.column(), goal_column);
 3823        let reversed = start_column < tail.column();
 3824
 3825        let selection_ranges = (start_row.0..=end_row.0)
 3826            .map(DisplayRow)
 3827            .filter_map(|row| {
 3828                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3829                    || start_column <= display_map.line_len(row))
 3830                    && !display_map.is_block_line(row)
 3831                {
 3832                    let start = display_map
 3833                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3834                        .to_point(display_map);
 3835                    let end = display_map
 3836                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3837                        .to_point(display_map);
 3838                    if reversed {
 3839                        Some(end..start)
 3840                    } else {
 3841                        Some(start..end)
 3842                    }
 3843                } else {
 3844                    None
 3845                }
 3846            })
 3847            .collect::<Vec<_>>();
 3848
 3849        let ranges = match columnar_state {
 3850            ColumnarSelectionState::FromMouse { .. } => {
 3851                let mut non_empty_ranges = selection_ranges
 3852                    .iter()
 3853                    .filter(|selection_range| selection_range.start != selection_range.end)
 3854                    .peekable();
 3855                if non_empty_ranges.peek().is_some() {
 3856                    non_empty_ranges.cloned().collect()
 3857                } else {
 3858                    selection_ranges
 3859                }
 3860            }
 3861            _ => selection_ranges,
 3862        };
 3863
 3864        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3865            s.select_ranges(ranges);
 3866        });
 3867        cx.notify();
 3868    }
 3869
 3870    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3871        self.selections
 3872            .all_adjusted(cx)
 3873            .iter()
 3874            .any(|selection| !selection.is_empty())
 3875    }
 3876
 3877    pub fn has_pending_nonempty_selection(&self) -> bool {
 3878        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3879            Some(Selection { start, end, .. }) => start != end,
 3880            None => false,
 3881        };
 3882
 3883        pending_nonempty_selection
 3884            || (self.columnar_selection_state.is_some()
 3885                && self.selections.disjoint_anchors().len() > 1)
 3886    }
 3887
 3888    pub fn has_pending_selection(&self) -> bool {
 3889        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3890    }
 3891
 3892    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3893        self.selection_mark_mode = false;
 3894        self.selection_drag_state = SelectionDragState::None;
 3895
 3896        if self.clear_expanded_diff_hunks(cx) {
 3897            cx.notify();
 3898            return;
 3899        }
 3900        if self.dismiss_menus_and_popups(true, window, cx) {
 3901            return;
 3902        }
 3903
 3904        if self.mode.is_full()
 3905            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3906        {
 3907            return;
 3908        }
 3909
 3910        cx.propagate();
 3911    }
 3912
 3913    pub fn dismiss_menus_and_popups(
 3914        &mut self,
 3915        is_user_requested: bool,
 3916        window: &mut Window,
 3917        cx: &mut Context<Self>,
 3918    ) -> bool {
 3919        if self.take_rename(false, window, cx).is_some() {
 3920            return true;
 3921        }
 3922
 3923        if hide_hover(self, cx) {
 3924            return true;
 3925        }
 3926
 3927        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3928            return true;
 3929        }
 3930
 3931        if self.hide_context_menu(window, cx).is_some() {
 3932            return true;
 3933        }
 3934
 3935        if self.mouse_context_menu.take().is_some() {
 3936            return true;
 3937        }
 3938
 3939        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3940            return true;
 3941        }
 3942
 3943        if self.snippet_stack.pop().is_some() {
 3944            return true;
 3945        }
 3946
 3947        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3948            self.dismiss_diagnostics(cx);
 3949            return true;
 3950        }
 3951
 3952        false
 3953    }
 3954
 3955    fn linked_editing_ranges_for(
 3956        &self,
 3957        selection: Range<text::Anchor>,
 3958        cx: &App,
 3959    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3960        if self.linked_edit_ranges.is_empty() {
 3961            return None;
 3962        }
 3963        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3964            selection.end.buffer_id.and_then(|end_buffer_id| {
 3965                if selection.start.buffer_id != Some(end_buffer_id) {
 3966                    return None;
 3967                }
 3968                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3969                let snapshot = buffer.read(cx).snapshot();
 3970                self.linked_edit_ranges
 3971                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3972                    .map(|ranges| (ranges, snapshot, buffer))
 3973            })?;
 3974        use text::ToOffset as TO;
 3975        // find offset from the start of current range to current cursor position
 3976        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3977
 3978        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3979        let start_difference = start_offset - start_byte_offset;
 3980        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3981        let end_difference = end_offset - start_byte_offset;
 3982        // Current range has associated linked ranges.
 3983        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3984        for range in linked_ranges.iter() {
 3985            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3986            let end_offset = start_offset + end_difference;
 3987            let start_offset = start_offset + start_difference;
 3988            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3989                continue;
 3990            }
 3991            if self.selections.disjoint_anchor_ranges().any(|s| {
 3992                if s.start.buffer_id != selection.start.buffer_id
 3993                    || s.end.buffer_id != selection.end.buffer_id
 3994                {
 3995                    return false;
 3996                }
 3997                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3998                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3999            }) {
 4000                continue;
 4001            }
 4002            let start = buffer_snapshot.anchor_after(start_offset);
 4003            let end = buffer_snapshot.anchor_after(end_offset);
 4004            linked_edits
 4005                .entry(buffer.clone())
 4006                .or_default()
 4007                .push(start..end);
 4008        }
 4009        Some(linked_edits)
 4010    }
 4011
 4012    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4013        let text: Arc<str> = text.into();
 4014
 4015        if self.read_only(cx) {
 4016            return;
 4017        }
 4018
 4019        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4020
 4021        let selections = self.selections.all_adjusted(cx);
 4022        let mut bracket_inserted = false;
 4023        let mut edits = Vec::new();
 4024        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4025        let mut new_selections = Vec::with_capacity(selections.len());
 4026        let mut new_autoclose_regions = Vec::new();
 4027        let snapshot = self.buffer.read(cx).read(cx);
 4028        let mut clear_linked_edit_ranges = false;
 4029
 4030        for (selection, autoclose_region) in
 4031            self.selections_with_autoclose_regions(selections, &snapshot)
 4032        {
 4033            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4034                // Determine if the inserted text matches the opening or closing
 4035                // bracket of any of this language's bracket pairs.
 4036                let mut bracket_pair = None;
 4037                let mut is_bracket_pair_start = false;
 4038                let mut is_bracket_pair_end = false;
 4039                if !text.is_empty() {
 4040                    let mut bracket_pair_matching_end = None;
 4041                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4042                    //  and they are removing the character that triggered IME popup.
 4043                    for (pair, enabled) in scope.brackets() {
 4044                        if !pair.close && !pair.surround {
 4045                            continue;
 4046                        }
 4047
 4048                        if enabled && pair.start.ends_with(text.as_ref()) {
 4049                            let prefix_len = pair.start.len() - text.len();
 4050                            let preceding_text_matches_prefix = prefix_len == 0
 4051                                || (selection.start.column >= (prefix_len as u32)
 4052                                    && snapshot.contains_str_at(
 4053                                        Point::new(
 4054                                            selection.start.row,
 4055                                            selection.start.column - (prefix_len as u32),
 4056                                        ),
 4057                                        &pair.start[..prefix_len],
 4058                                    ));
 4059                            if preceding_text_matches_prefix {
 4060                                bracket_pair = Some(pair.clone());
 4061                                is_bracket_pair_start = true;
 4062                                break;
 4063                            }
 4064                        }
 4065                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4066                        {
 4067                            // take first bracket pair matching end, but don't break in case a later bracket
 4068                            // pair matches start
 4069                            bracket_pair_matching_end = Some(pair.clone());
 4070                        }
 4071                    }
 4072                    if let Some(end) = bracket_pair_matching_end
 4073                        && bracket_pair.is_none()
 4074                    {
 4075                        bracket_pair = Some(end);
 4076                        is_bracket_pair_end = true;
 4077                    }
 4078                }
 4079
 4080                if let Some(bracket_pair) = bracket_pair {
 4081                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4082                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4083                    let auto_surround =
 4084                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4085                    if selection.is_empty() {
 4086                        if is_bracket_pair_start {
 4087                            // If the inserted text is a suffix of an opening bracket and the
 4088                            // selection is preceded by the rest of the opening bracket, then
 4089                            // insert the closing bracket.
 4090                            let following_text_allows_autoclose = snapshot
 4091                                .chars_at(selection.start)
 4092                                .next()
 4093                                .is_none_or(|c| scope.should_autoclose_before(c));
 4094
 4095                            let preceding_text_allows_autoclose = selection.start.column == 0
 4096                                || snapshot
 4097                                    .reversed_chars_at(selection.start)
 4098                                    .next()
 4099                                    .is_none_or(|c| {
 4100                                        bracket_pair.start != bracket_pair.end
 4101                                            || !snapshot
 4102                                                .char_classifier_at(selection.start)
 4103                                                .is_word(c)
 4104                                    });
 4105
 4106                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4107                                && bracket_pair.start.len() == 1
 4108                            {
 4109                                let target = bracket_pair.start.chars().next().unwrap();
 4110                                let current_line_count = snapshot
 4111                                    .reversed_chars_at(selection.start)
 4112                                    .take_while(|&c| c != '\n')
 4113                                    .filter(|&c| c == target)
 4114                                    .count();
 4115                                current_line_count % 2 == 1
 4116                            } else {
 4117                                false
 4118                            };
 4119
 4120                            if autoclose
 4121                                && bracket_pair.close
 4122                                && following_text_allows_autoclose
 4123                                && preceding_text_allows_autoclose
 4124                                && !is_closing_quote
 4125                            {
 4126                                let anchor = snapshot.anchor_before(selection.end);
 4127                                new_selections.push((selection.map(|_| anchor), text.len()));
 4128                                new_autoclose_regions.push((
 4129                                    anchor,
 4130                                    text.len(),
 4131                                    selection.id,
 4132                                    bracket_pair.clone(),
 4133                                ));
 4134                                edits.push((
 4135                                    selection.range(),
 4136                                    format!("{}{}", text, bracket_pair.end).into(),
 4137                                ));
 4138                                bracket_inserted = true;
 4139                                continue;
 4140                            }
 4141                        }
 4142
 4143                        if let Some(region) = autoclose_region {
 4144                            // If the selection is followed by an auto-inserted closing bracket,
 4145                            // then don't insert that closing bracket again; just move the selection
 4146                            // past the closing bracket.
 4147                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4148                                && text.as_ref() == region.pair.end.as_str()
 4149                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4150                            if should_skip {
 4151                                let anchor = snapshot.anchor_after(selection.end);
 4152                                new_selections
 4153                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4154                                continue;
 4155                            }
 4156                        }
 4157
 4158                        let always_treat_brackets_as_autoclosed = snapshot
 4159                            .language_settings_at(selection.start, cx)
 4160                            .always_treat_brackets_as_autoclosed;
 4161                        if always_treat_brackets_as_autoclosed
 4162                            && is_bracket_pair_end
 4163                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4164                        {
 4165                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4166                            // and the inserted text is a closing bracket and the selection is followed
 4167                            // by the closing bracket then move the selection past the closing bracket.
 4168                            let anchor = snapshot.anchor_after(selection.end);
 4169                            new_selections.push((selection.map(|_| anchor), text.len()));
 4170                            continue;
 4171                        }
 4172                    }
 4173                    // If an opening bracket is 1 character long and is typed while
 4174                    // text is selected, then surround that text with the bracket pair.
 4175                    else if auto_surround
 4176                        && bracket_pair.surround
 4177                        && is_bracket_pair_start
 4178                        && bracket_pair.start.chars().count() == 1
 4179                    {
 4180                        edits.push((selection.start..selection.start, text.clone()));
 4181                        edits.push((
 4182                            selection.end..selection.end,
 4183                            bracket_pair.end.as_str().into(),
 4184                        ));
 4185                        bracket_inserted = true;
 4186                        new_selections.push((
 4187                            Selection {
 4188                                id: selection.id,
 4189                                start: snapshot.anchor_after(selection.start),
 4190                                end: snapshot.anchor_before(selection.end),
 4191                                reversed: selection.reversed,
 4192                                goal: selection.goal,
 4193                            },
 4194                            0,
 4195                        ));
 4196                        continue;
 4197                    }
 4198                }
 4199            }
 4200
 4201            if self.auto_replace_emoji_shortcode
 4202                && selection.is_empty()
 4203                && text.as_ref().ends_with(':')
 4204                && let Some(possible_emoji_short_code) =
 4205                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4206                && !possible_emoji_short_code.is_empty()
 4207                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4208            {
 4209                let emoji_shortcode_start = Point::new(
 4210                    selection.start.row,
 4211                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4212                );
 4213
 4214                // Remove shortcode from buffer
 4215                edits.push((
 4216                    emoji_shortcode_start..selection.start,
 4217                    "".to_string().into(),
 4218                ));
 4219                new_selections.push((
 4220                    Selection {
 4221                        id: selection.id,
 4222                        start: snapshot.anchor_after(emoji_shortcode_start),
 4223                        end: snapshot.anchor_before(selection.start),
 4224                        reversed: selection.reversed,
 4225                        goal: selection.goal,
 4226                    },
 4227                    0,
 4228                ));
 4229
 4230                // Insert emoji
 4231                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4232                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4233                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4234
 4235                continue;
 4236            }
 4237
 4238            // If not handling any auto-close operation, then just replace the selected
 4239            // text with the given input and move the selection to the end of the
 4240            // newly inserted text.
 4241            let anchor = snapshot.anchor_after(selection.end);
 4242            if !self.linked_edit_ranges.is_empty() {
 4243                let start_anchor = snapshot.anchor_before(selection.start);
 4244
 4245                let is_word_char = text.chars().next().is_none_or(|char| {
 4246                    let classifier = snapshot
 4247                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4248                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4249                    classifier.is_word(char)
 4250                });
 4251
 4252                if is_word_char {
 4253                    if let Some(ranges) = self
 4254                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4255                    {
 4256                        for (buffer, edits) in ranges {
 4257                            linked_edits
 4258                                .entry(buffer.clone())
 4259                                .or_default()
 4260                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4261                        }
 4262                    }
 4263                } else {
 4264                    clear_linked_edit_ranges = true;
 4265                }
 4266            }
 4267
 4268            new_selections.push((selection.map(|_| anchor), 0));
 4269            edits.push((selection.start..selection.end, text.clone()));
 4270        }
 4271
 4272        drop(snapshot);
 4273
 4274        self.transact(window, cx, |this, window, cx| {
 4275            if clear_linked_edit_ranges {
 4276                this.linked_edit_ranges.clear();
 4277            }
 4278            let initial_buffer_versions =
 4279                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4280
 4281            this.buffer.update(cx, |buffer, cx| {
 4282                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4283            });
 4284            for (buffer, edits) in linked_edits {
 4285                buffer.update(cx, |buffer, cx| {
 4286                    let snapshot = buffer.snapshot();
 4287                    let edits = edits
 4288                        .into_iter()
 4289                        .map(|(range, text)| {
 4290                            use text::ToPoint as TP;
 4291                            let end_point = TP::to_point(&range.end, &snapshot);
 4292                            let start_point = TP::to_point(&range.start, &snapshot);
 4293                            (start_point..end_point, text)
 4294                        })
 4295                        .sorted_by_key(|(range, _)| range.start);
 4296                    buffer.edit(edits, None, cx);
 4297                })
 4298            }
 4299            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4300            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4301            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4302            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4303                .zip(new_selection_deltas)
 4304                .map(|(selection, delta)| Selection {
 4305                    id: selection.id,
 4306                    start: selection.start + delta,
 4307                    end: selection.end + delta,
 4308                    reversed: selection.reversed,
 4309                    goal: SelectionGoal::None,
 4310                })
 4311                .collect::<Vec<_>>();
 4312
 4313            let mut i = 0;
 4314            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4315                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4316                let start = map.buffer_snapshot.anchor_before(position);
 4317                let end = map.buffer_snapshot.anchor_after(position);
 4318                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4319                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4320                        Ordering::Less => i += 1,
 4321                        Ordering::Greater => break,
 4322                        Ordering::Equal => {
 4323                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4324                                Ordering::Less => i += 1,
 4325                                Ordering::Equal => break,
 4326                                Ordering::Greater => break,
 4327                            }
 4328                        }
 4329                    }
 4330                }
 4331                this.autoclose_regions.insert(
 4332                    i,
 4333                    AutocloseRegion {
 4334                        selection_id,
 4335                        range: start..end,
 4336                        pair,
 4337                    },
 4338                );
 4339            }
 4340
 4341            let had_active_edit_prediction = this.has_active_edit_prediction();
 4342            this.change_selections(
 4343                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4344                window,
 4345                cx,
 4346                |s| s.select(new_selections),
 4347            );
 4348
 4349            if !bracket_inserted
 4350                && let Some(on_type_format_task) =
 4351                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4352            {
 4353                on_type_format_task.detach_and_log_err(cx);
 4354            }
 4355
 4356            let editor_settings = EditorSettings::get_global(cx);
 4357            if bracket_inserted
 4358                && (editor_settings.auto_signature_help
 4359                    || editor_settings.show_signature_help_after_edits)
 4360            {
 4361                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4362            }
 4363
 4364            let trigger_in_words =
 4365                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4366            if this.hard_wrap.is_some() {
 4367                let latest: Range<Point> = this.selections.newest(cx).range();
 4368                if latest.is_empty()
 4369                    && this
 4370                        .buffer()
 4371                        .read(cx)
 4372                        .snapshot(cx)
 4373                        .line_len(MultiBufferRow(latest.start.row))
 4374                        == latest.start.column
 4375                {
 4376                    this.rewrap_impl(
 4377                        RewrapOptions {
 4378                            override_language_settings: true,
 4379                            preserve_existing_whitespace: true,
 4380                        },
 4381                        cx,
 4382                    )
 4383                }
 4384            }
 4385            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4386            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4387            this.refresh_edit_prediction(true, false, window, cx);
 4388            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4389        });
 4390    }
 4391
 4392    fn find_possible_emoji_shortcode_at_position(
 4393        snapshot: &MultiBufferSnapshot,
 4394        position: Point,
 4395    ) -> Option<String> {
 4396        let mut chars = Vec::new();
 4397        let mut found_colon = false;
 4398        for char in snapshot.reversed_chars_at(position).take(100) {
 4399            // Found a possible emoji shortcode in the middle of the buffer
 4400            if found_colon {
 4401                if char.is_whitespace() {
 4402                    chars.reverse();
 4403                    return Some(chars.iter().collect());
 4404                }
 4405                // If the previous character is not a whitespace, we are in the middle of a word
 4406                // and we only want to complete the shortcode if the word is made up of other emojis
 4407                let mut containing_word = String::new();
 4408                for ch in snapshot
 4409                    .reversed_chars_at(position)
 4410                    .skip(chars.len() + 1)
 4411                    .take(100)
 4412                {
 4413                    if ch.is_whitespace() {
 4414                        break;
 4415                    }
 4416                    containing_word.push(ch);
 4417                }
 4418                let containing_word = containing_word.chars().rev().collect::<String>();
 4419                if util::word_consists_of_emojis(containing_word.as_str()) {
 4420                    chars.reverse();
 4421                    return Some(chars.iter().collect());
 4422                }
 4423            }
 4424
 4425            if char.is_whitespace() || !char.is_ascii() {
 4426                return None;
 4427            }
 4428            if char == ':' {
 4429                found_colon = true;
 4430            } else {
 4431                chars.push(char);
 4432            }
 4433        }
 4434        // Found a possible emoji shortcode at the beginning of the buffer
 4435        chars.reverse();
 4436        Some(chars.iter().collect())
 4437    }
 4438
 4439    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4440        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4441        self.transact(window, cx, |this, window, cx| {
 4442            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4443                let selections = this.selections.all::<usize>(cx);
 4444                let multi_buffer = this.buffer.read(cx);
 4445                let buffer = multi_buffer.snapshot(cx);
 4446                selections
 4447                    .iter()
 4448                    .map(|selection| {
 4449                        let start_point = selection.start.to_point(&buffer);
 4450                        let mut existing_indent =
 4451                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4452                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4453                        let start = selection.start;
 4454                        let end = selection.end;
 4455                        let selection_is_empty = start == end;
 4456                        let language_scope = buffer.language_scope_at(start);
 4457                        let (
 4458                            comment_delimiter,
 4459                            doc_delimiter,
 4460                            insert_extra_newline,
 4461                            indent_on_newline,
 4462                            indent_on_extra_newline,
 4463                        ) = if let Some(language) = &language_scope {
 4464                            let mut insert_extra_newline =
 4465                                insert_extra_newline_brackets(&buffer, start..end, language)
 4466                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4467
 4468                            // Comment extension on newline is allowed only for cursor selections
 4469                            let comment_delimiter = maybe!({
 4470                                if !selection_is_empty {
 4471                                    return None;
 4472                                }
 4473
 4474                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4475                                    return None;
 4476                                }
 4477
 4478                                let delimiters = language.line_comment_prefixes();
 4479                                let max_len_of_delimiter =
 4480                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4481                                let (snapshot, range) =
 4482                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4483
 4484                                let num_of_whitespaces = snapshot
 4485                                    .chars_for_range(range.clone())
 4486                                    .take_while(|c| c.is_whitespace())
 4487                                    .count();
 4488                                let comment_candidate = snapshot
 4489                                    .chars_for_range(range.clone())
 4490                                    .skip(num_of_whitespaces)
 4491                                    .take(max_len_of_delimiter)
 4492                                    .collect::<String>();
 4493                                let (delimiter, trimmed_len) = delimiters
 4494                                    .iter()
 4495                                    .filter_map(|delimiter| {
 4496                                        let prefix = delimiter.trim_end();
 4497                                        if comment_candidate.starts_with(prefix) {
 4498                                            Some((delimiter, prefix.len()))
 4499                                        } else {
 4500                                            None
 4501                                        }
 4502                                    })
 4503                                    .max_by_key(|(_, len)| *len)?;
 4504
 4505                                if let Some(BlockCommentConfig {
 4506                                    start: block_start, ..
 4507                                }) = language.block_comment()
 4508                                {
 4509                                    let block_start_trimmed = block_start.trim_end();
 4510                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4511                                        let line_content = snapshot
 4512                                            .chars_for_range(range)
 4513                                            .skip(num_of_whitespaces)
 4514                                            .take(block_start_trimmed.len())
 4515                                            .collect::<String>();
 4516
 4517                                        if line_content.starts_with(block_start_trimmed) {
 4518                                            return None;
 4519                                        }
 4520                                    }
 4521                                }
 4522
 4523                                let cursor_is_placed_after_comment_marker =
 4524                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4525                                if cursor_is_placed_after_comment_marker {
 4526                                    Some(delimiter.clone())
 4527                                } else {
 4528                                    None
 4529                                }
 4530                            });
 4531
 4532                            let mut indent_on_newline = IndentSize::spaces(0);
 4533                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4534
 4535                            let doc_delimiter = maybe!({
 4536                                if !selection_is_empty {
 4537                                    return None;
 4538                                }
 4539
 4540                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4541                                    return None;
 4542                                }
 4543
 4544                                let BlockCommentConfig {
 4545                                    start: start_tag,
 4546                                    end: end_tag,
 4547                                    prefix: delimiter,
 4548                                    tab_size: len,
 4549                                } = language.documentation_comment()?;
 4550                                let is_within_block_comment = buffer
 4551                                    .language_scope_at(start_point)
 4552                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4553                                if !is_within_block_comment {
 4554                                    return None;
 4555                                }
 4556
 4557                                let (snapshot, range) =
 4558                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4559
 4560                                let num_of_whitespaces = snapshot
 4561                                    .chars_for_range(range.clone())
 4562                                    .take_while(|c| c.is_whitespace())
 4563                                    .count();
 4564
 4565                                // 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.
 4566                                let column = start_point.column;
 4567                                let cursor_is_after_start_tag = {
 4568                                    let start_tag_len = start_tag.len();
 4569                                    let start_tag_line = snapshot
 4570                                        .chars_for_range(range.clone())
 4571                                        .skip(num_of_whitespaces)
 4572                                        .take(start_tag_len)
 4573                                        .collect::<String>();
 4574                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4575                                        num_of_whitespaces + start_tag_len <= column as usize
 4576                                    } else {
 4577                                        false
 4578                                    }
 4579                                };
 4580
 4581                                let cursor_is_after_delimiter = {
 4582                                    let delimiter_trim = delimiter.trim_end();
 4583                                    let delimiter_line = snapshot
 4584                                        .chars_for_range(range.clone())
 4585                                        .skip(num_of_whitespaces)
 4586                                        .take(delimiter_trim.len())
 4587                                        .collect::<String>();
 4588                                    if delimiter_line.starts_with(delimiter_trim) {
 4589                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4590                                    } else {
 4591                                        false
 4592                                    }
 4593                                };
 4594
 4595                                let cursor_is_before_end_tag_if_exists = {
 4596                                    let mut char_position = 0u32;
 4597                                    let mut end_tag_offset = None;
 4598
 4599                                    'outer: for chunk in snapshot.text_for_range(range) {
 4600                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4601                                            let chars_before_match =
 4602                                                chunk[..byte_pos].chars().count() as u32;
 4603                                            end_tag_offset =
 4604                                                Some(char_position + chars_before_match);
 4605                                            break 'outer;
 4606                                        }
 4607                                        char_position += chunk.chars().count() as u32;
 4608                                    }
 4609
 4610                                    if let Some(end_tag_offset) = end_tag_offset {
 4611                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4612                                        if cursor_is_after_start_tag {
 4613                                            if cursor_is_before_end_tag {
 4614                                                insert_extra_newline = true;
 4615                                            }
 4616                                            let cursor_is_at_start_of_end_tag =
 4617                                                column == end_tag_offset;
 4618                                            if cursor_is_at_start_of_end_tag {
 4619                                                indent_on_extra_newline.len = *len;
 4620                                            }
 4621                                        }
 4622                                        cursor_is_before_end_tag
 4623                                    } else {
 4624                                        true
 4625                                    }
 4626                                };
 4627
 4628                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4629                                    && cursor_is_before_end_tag_if_exists
 4630                                {
 4631                                    if cursor_is_after_start_tag {
 4632                                        indent_on_newline.len = *len;
 4633                                    }
 4634                                    Some(delimiter.clone())
 4635                                } else {
 4636                                    None
 4637                                }
 4638                            });
 4639
 4640                            (
 4641                                comment_delimiter,
 4642                                doc_delimiter,
 4643                                insert_extra_newline,
 4644                                indent_on_newline,
 4645                                indent_on_extra_newline,
 4646                            )
 4647                        } else {
 4648                            (
 4649                                None,
 4650                                None,
 4651                                false,
 4652                                IndentSize::default(),
 4653                                IndentSize::default(),
 4654                            )
 4655                        };
 4656
 4657                        let prevent_auto_indent = doc_delimiter.is_some();
 4658                        let delimiter = comment_delimiter.or(doc_delimiter);
 4659
 4660                        let capacity_for_delimiter =
 4661                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4662                        let mut new_text = String::with_capacity(
 4663                            1 + capacity_for_delimiter
 4664                                + existing_indent.len as usize
 4665                                + indent_on_newline.len as usize
 4666                                + indent_on_extra_newline.len as usize,
 4667                        );
 4668                        new_text.push('\n');
 4669                        new_text.extend(existing_indent.chars());
 4670                        new_text.extend(indent_on_newline.chars());
 4671
 4672                        if let Some(delimiter) = &delimiter {
 4673                            new_text.push_str(delimiter);
 4674                        }
 4675
 4676                        if insert_extra_newline {
 4677                            new_text.push('\n');
 4678                            new_text.extend(existing_indent.chars());
 4679                            new_text.extend(indent_on_extra_newline.chars());
 4680                        }
 4681
 4682                        let anchor = buffer.anchor_after(end);
 4683                        let new_selection = selection.map(|_| anchor);
 4684                        (
 4685                            ((start..end, new_text), prevent_auto_indent),
 4686                            (insert_extra_newline, new_selection),
 4687                        )
 4688                    })
 4689                    .unzip()
 4690            };
 4691
 4692            let mut auto_indent_edits = Vec::new();
 4693            let mut edits = Vec::new();
 4694            for (edit, prevent_auto_indent) in edits_with_flags {
 4695                if prevent_auto_indent {
 4696                    edits.push(edit);
 4697                } else {
 4698                    auto_indent_edits.push(edit);
 4699                }
 4700            }
 4701            if !edits.is_empty() {
 4702                this.edit(edits, cx);
 4703            }
 4704            if !auto_indent_edits.is_empty() {
 4705                this.edit_with_autoindent(auto_indent_edits, cx);
 4706            }
 4707
 4708            let buffer = this.buffer.read(cx).snapshot(cx);
 4709            let new_selections = selection_info
 4710                .into_iter()
 4711                .map(|(extra_newline_inserted, new_selection)| {
 4712                    let mut cursor = new_selection.end.to_point(&buffer);
 4713                    if extra_newline_inserted {
 4714                        cursor.row -= 1;
 4715                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4716                    }
 4717                    new_selection.map(|_| cursor)
 4718                })
 4719                .collect();
 4720
 4721            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4722            this.refresh_edit_prediction(true, false, window, cx);
 4723        });
 4724    }
 4725
 4726    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4727        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4728
 4729        let buffer = self.buffer.read(cx);
 4730        let snapshot = buffer.snapshot(cx);
 4731
 4732        let mut edits = Vec::new();
 4733        let mut rows = Vec::new();
 4734
 4735        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4736            let cursor = selection.head();
 4737            let row = cursor.row;
 4738
 4739            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4740
 4741            let newline = "\n".to_string();
 4742            edits.push((start_of_line..start_of_line, newline));
 4743
 4744            rows.push(row + rows_inserted as u32);
 4745        }
 4746
 4747        self.transact(window, cx, |editor, window, cx| {
 4748            editor.edit(edits, cx);
 4749
 4750            editor.change_selections(Default::default(), window, cx, |s| {
 4751                let mut index = 0;
 4752                s.move_cursors_with(|map, _, _| {
 4753                    let row = rows[index];
 4754                    index += 1;
 4755
 4756                    let point = Point::new(row, 0);
 4757                    let boundary = map.next_line_boundary(point).1;
 4758                    let clipped = map.clip_point(boundary, Bias::Left);
 4759
 4760                    (clipped, SelectionGoal::None)
 4761                });
 4762            });
 4763
 4764            let mut indent_edits = Vec::new();
 4765            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4766            for row in rows {
 4767                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4768                for (row, indent) in indents {
 4769                    if indent.len == 0 {
 4770                        continue;
 4771                    }
 4772
 4773                    let text = match indent.kind {
 4774                        IndentKind::Space => " ".repeat(indent.len as usize),
 4775                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4776                    };
 4777                    let point = Point::new(row.0, 0);
 4778                    indent_edits.push((point..point, text));
 4779                }
 4780            }
 4781            editor.edit(indent_edits, cx);
 4782        });
 4783    }
 4784
 4785    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4786        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4787
 4788        let buffer = self.buffer.read(cx);
 4789        let snapshot = buffer.snapshot(cx);
 4790
 4791        let mut edits = Vec::new();
 4792        let mut rows = Vec::new();
 4793        let mut rows_inserted = 0;
 4794
 4795        for selection in self.selections.all_adjusted(cx) {
 4796            let cursor = selection.head();
 4797            let row = cursor.row;
 4798
 4799            let point = Point::new(row + 1, 0);
 4800            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4801
 4802            let newline = "\n".to_string();
 4803            edits.push((start_of_line..start_of_line, newline));
 4804
 4805            rows_inserted += 1;
 4806            rows.push(row + rows_inserted);
 4807        }
 4808
 4809        self.transact(window, cx, |editor, window, cx| {
 4810            editor.edit(edits, cx);
 4811
 4812            editor.change_selections(Default::default(), window, cx, |s| {
 4813                let mut index = 0;
 4814                s.move_cursors_with(|map, _, _| {
 4815                    let row = rows[index];
 4816                    index += 1;
 4817
 4818                    let point = Point::new(row, 0);
 4819                    let boundary = map.next_line_boundary(point).1;
 4820                    let clipped = map.clip_point(boundary, Bias::Left);
 4821
 4822                    (clipped, SelectionGoal::None)
 4823                });
 4824            });
 4825
 4826            let mut indent_edits = Vec::new();
 4827            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4828            for row in rows {
 4829                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4830                for (row, indent) in indents {
 4831                    if indent.len == 0 {
 4832                        continue;
 4833                    }
 4834
 4835                    let text = match indent.kind {
 4836                        IndentKind::Space => " ".repeat(indent.len as usize),
 4837                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4838                    };
 4839                    let point = Point::new(row.0, 0);
 4840                    indent_edits.push((point..point, text));
 4841                }
 4842            }
 4843            editor.edit(indent_edits, cx);
 4844        });
 4845    }
 4846
 4847    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4848        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4849            original_indent_columns: Vec::new(),
 4850        });
 4851        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4852    }
 4853
 4854    fn insert_with_autoindent_mode(
 4855        &mut self,
 4856        text: &str,
 4857        autoindent_mode: Option<AutoindentMode>,
 4858        window: &mut Window,
 4859        cx: &mut Context<Self>,
 4860    ) {
 4861        if self.read_only(cx) {
 4862            return;
 4863        }
 4864
 4865        let text: Arc<str> = text.into();
 4866        self.transact(window, cx, |this, window, cx| {
 4867            let old_selections = this.selections.all_adjusted(cx);
 4868            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4869                let anchors = {
 4870                    let snapshot = buffer.read(cx);
 4871                    old_selections
 4872                        .iter()
 4873                        .map(|s| {
 4874                            let anchor = snapshot.anchor_after(s.head());
 4875                            s.map(|_| anchor)
 4876                        })
 4877                        .collect::<Vec<_>>()
 4878                };
 4879                buffer.edit(
 4880                    old_selections
 4881                        .iter()
 4882                        .map(|s| (s.start..s.end, text.clone())),
 4883                    autoindent_mode,
 4884                    cx,
 4885                );
 4886                anchors
 4887            });
 4888
 4889            this.change_selections(Default::default(), window, cx, |s| {
 4890                s.select_anchors(selection_anchors);
 4891            });
 4892
 4893            cx.notify();
 4894        });
 4895    }
 4896
 4897    fn trigger_completion_on_input(
 4898        &mut self,
 4899        text: &str,
 4900        trigger_in_words: bool,
 4901        window: &mut Window,
 4902        cx: &mut Context<Self>,
 4903    ) {
 4904        let completions_source = self
 4905            .context_menu
 4906            .borrow()
 4907            .as_ref()
 4908            .and_then(|menu| match menu {
 4909                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4910                CodeContextMenu::CodeActions(_) => None,
 4911            });
 4912
 4913        match completions_source {
 4914            Some(CompletionsMenuSource::Words { .. }) => {
 4915                self.open_or_update_completions_menu(
 4916                    Some(CompletionsMenuSource::Words {
 4917                        ignore_threshold: false,
 4918                    }),
 4919                    None,
 4920                    window,
 4921                    cx,
 4922                );
 4923            }
 4924            Some(CompletionsMenuSource::Normal)
 4925            | Some(CompletionsMenuSource::SnippetChoices)
 4926            | None
 4927                if self.is_completion_trigger(
 4928                    text,
 4929                    trigger_in_words,
 4930                    completions_source.is_some(),
 4931                    cx,
 4932                ) =>
 4933            {
 4934                self.show_completions(
 4935                    &ShowCompletions {
 4936                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4937                    },
 4938                    window,
 4939                    cx,
 4940                )
 4941            }
 4942            _ => {
 4943                self.hide_context_menu(window, cx);
 4944            }
 4945        }
 4946    }
 4947
 4948    fn is_completion_trigger(
 4949        &self,
 4950        text: &str,
 4951        trigger_in_words: bool,
 4952        menu_is_open: bool,
 4953        cx: &mut Context<Self>,
 4954    ) -> bool {
 4955        let position = self.selections.newest_anchor().head();
 4956        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4957            return false;
 4958        };
 4959
 4960        if let Some(completion_provider) = &self.completion_provider {
 4961            completion_provider.is_completion_trigger(
 4962                &buffer,
 4963                position.text_anchor,
 4964                text,
 4965                trigger_in_words,
 4966                menu_is_open,
 4967                cx,
 4968            )
 4969        } else {
 4970            false
 4971        }
 4972    }
 4973
 4974    /// If any empty selections is touching the start of its innermost containing autoclose
 4975    /// region, expand it to select the brackets.
 4976    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4977        let selections = self.selections.all::<usize>(cx);
 4978        let buffer = self.buffer.read(cx).read(cx);
 4979        let new_selections = self
 4980            .selections_with_autoclose_regions(selections, &buffer)
 4981            .map(|(mut selection, region)| {
 4982                if !selection.is_empty() {
 4983                    return selection;
 4984                }
 4985
 4986                if let Some(region) = region {
 4987                    let mut range = region.range.to_offset(&buffer);
 4988                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4989                        range.start -= region.pair.start.len();
 4990                        if buffer.contains_str_at(range.start, &region.pair.start)
 4991                            && buffer.contains_str_at(range.end, &region.pair.end)
 4992                        {
 4993                            range.end += region.pair.end.len();
 4994                            selection.start = range.start;
 4995                            selection.end = range.end;
 4996
 4997                            return selection;
 4998                        }
 4999                    }
 5000                }
 5001
 5002                let always_treat_brackets_as_autoclosed = buffer
 5003                    .language_settings_at(selection.start, cx)
 5004                    .always_treat_brackets_as_autoclosed;
 5005
 5006                if !always_treat_brackets_as_autoclosed {
 5007                    return selection;
 5008                }
 5009
 5010                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5011                    for (pair, enabled) in scope.brackets() {
 5012                        if !enabled || !pair.close {
 5013                            continue;
 5014                        }
 5015
 5016                        if buffer.contains_str_at(selection.start, &pair.end) {
 5017                            let pair_start_len = pair.start.len();
 5018                            if buffer.contains_str_at(
 5019                                selection.start.saturating_sub(pair_start_len),
 5020                                &pair.start,
 5021                            ) {
 5022                                selection.start -= pair_start_len;
 5023                                selection.end += pair.end.len();
 5024
 5025                                return selection;
 5026                            }
 5027                        }
 5028                    }
 5029                }
 5030
 5031                selection
 5032            })
 5033            .collect();
 5034
 5035        drop(buffer);
 5036        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5037            selections.select(new_selections)
 5038        });
 5039    }
 5040
 5041    /// Iterate the given selections, and for each one, find the smallest surrounding
 5042    /// autoclose region. This uses the ordering of the selections and the autoclose
 5043    /// regions to avoid repeated comparisons.
 5044    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5045        &'a self,
 5046        selections: impl IntoIterator<Item = Selection<D>>,
 5047        buffer: &'a MultiBufferSnapshot,
 5048    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5049        let mut i = 0;
 5050        let mut regions = self.autoclose_regions.as_slice();
 5051        selections.into_iter().map(move |selection| {
 5052            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5053
 5054            let mut enclosing = None;
 5055            while let Some(pair_state) = regions.get(i) {
 5056                if pair_state.range.end.to_offset(buffer) < range.start {
 5057                    regions = &regions[i + 1..];
 5058                    i = 0;
 5059                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5060                    break;
 5061                } else {
 5062                    if pair_state.selection_id == selection.id {
 5063                        enclosing = Some(pair_state);
 5064                    }
 5065                    i += 1;
 5066                }
 5067            }
 5068
 5069            (selection, enclosing)
 5070        })
 5071    }
 5072
 5073    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5074    fn invalidate_autoclose_regions(
 5075        &mut self,
 5076        mut selections: &[Selection<Anchor>],
 5077        buffer: &MultiBufferSnapshot,
 5078    ) {
 5079        self.autoclose_regions.retain(|state| {
 5080            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5081                return false;
 5082            }
 5083
 5084            let mut i = 0;
 5085            while let Some(selection) = selections.get(i) {
 5086                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5087                    selections = &selections[1..];
 5088                    continue;
 5089                }
 5090                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5091                    break;
 5092                }
 5093                if selection.id == state.selection_id {
 5094                    return true;
 5095                } else {
 5096                    i += 1;
 5097                }
 5098            }
 5099            false
 5100        });
 5101    }
 5102
 5103    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5104        let offset = position.to_offset(buffer);
 5105        let (word_range, kind) =
 5106            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5107        if offset > word_range.start && kind == Some(CharKind::Word) {
 5108            Some(
 5109                buffer
 5110                    .text_for_range(word_range.start..offset)
 5111                    .collect::<String>(),
 5112            )
 5113        } else {
 5114            None
 5115        }
 5116    }
 5117
 5118    pub fn toggle_inline_values(
 5119        &mut self,
 5120        _: &ToggleInlineValues,
 5121        _: &mut Window,
 5122        cx: &mut Context<Self>,
 5123    ) {
 5124        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5125
 5126        self.refresh_inline_values(cx);
 5127    }
 5128
 5129    pub fn toggle_inlay_hints(
 5130        &mut self,
 5131        _: &ToggleInlayHints,
 5132        _: &mut Window,
 5133        cx: &mut Context<Self>,
 5134    ) {
 5135        self.refresh_inlay_hints(
 5136            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5137            cx,
 5138        );
 5139    }
 5140
 5141    pub fn inlay_hints_enabled(&self) -> bool {
 5142        self.inlay_hint_cache.enabled
 5143    }
 5144
 5145    pub fn inline_values_enabled(&self) -> bool {
 5146        self.inline_value_cache.enabled
 5147    }
 5148
 5149    #[cfg(any(test, feature = "test-support"))]
 5150    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5151        self.display_map
 5152            .read(cx)
 5153            .current_inlays()
 5154            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5155            .cloned()
 5156            .collect()
 5157    }
 5158
 5159    #[cfg(any(test, feature = "test-support"))]
 5160    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5161        self.display_map
 5162            .read(cx)
 5163            .current_inlays()
 5164            .cloned()
 5165            .collect()
 5166    }
 5167
 5168    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5169        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5170            return;
 5171        }
 5172
 5173        let reason_description = reason.description();
 5174        let ignore_debounce = matches!(
 5175            reason,
 5176            InlayHintRefreshReason::SettingsChange(_)
 5177                | InlayHintRefreshReason::Toggle(_)
 5178                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5179                | InlayHintRefreshReason::ModifiersChanged(_)
 5180        );
 5181        let (invalidate_cache, required_languages) = match reason {
 5182            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5183                match self.inlay_hint_cache.modifiers_override(enabled) {
 5184                    Some(enabled) => {
 5185                        if enabled {
 5186                            (InvalidationStrategy::RefreshRequested, None)
 5187                        } else {
 5188                            self.splice_inlays(
 5189                                &self
 5190                                    .visible_inlay_hints(cx)
 5191                                    .iter()
 5192                                    .map(|inlay| inlay.id)
 5193                                    .collect::<Vec<InlayId>>(),
 5194                                Vec::new(),
 5195                                cx,
 5196                            );
 5197                            return;
 5198                        }
 5199                    }
 5200                    None => return,
 5201                }
 5202            }
 5203            InlayHintRefreshReason::Toggle(enabled) => {
 5204                if self.inlay_hint_cache.toggle(enabled) {
 5205                    if enabled {
 5206                        (InvalidationStrategy::RefreshRequested, None)
 5207                    } else {
 5208                        self.splice_inlays(
 5209                            &self
 5210                                .visible_inlay_hints(cx)
 5211                                .iter()
 5212                                .map(|inlay| inlay.id)
 5213                                .collect::<Vec<InlayId>>(),
 5214                            Vec::new(),
 5215                            cx,
 5216                        );
 5217                        return;
 5218                    }
 5219                } else {
 5220                    return;
 5221                }
 5222            }
 5223            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5224                match self.inlay_hint_cache.update_settings(
 5225                    &self.buffer,
 5226                    new_settings,
 5227                    self.visible_inlay_hints(cx),
 5228                    cx,
 5229                ) {
 5230                    ControlFlow::Break(Some(InlaySplice {
 5231                        to_remove,
 5232                        to_insert,
 5233                    })) => {
 5234                        self.splice_inlays(&to_remove, to_insert, cx);
 5235                        return;
 5236                    }
 5237                    ControlFlow::Break(None) => return,
 5238                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5239                }
 5240            }
 5241            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5242                if let Some(InlaySplice {
 5243                    to_remove,
 5244                    to_insert,
 5245                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5246                {
 5247                    self.splice_inlays(&to_remove, to_insert, cx);
 5248                }
 5249                self.display_map.update(cx, |display_map, _| {
 5250                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5251                });
 5252                return;
 5253            }
 5254            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5255            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5256                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5257            }
 5258            InlayHintRefreshReason::RefreshRequested => {
 5259                (InvalidationStrategy::RefreshRequested, None)
 5260            }
 5261        };
 5262
 5263        if let Some(InlaySplice {
 5264            to_remove,
 5265            to_insert,
 5266        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5267            reason_description,
 5268            self.visible_excerpts(required_languages.as_ref(), cx),
 5269            invalidate_cache,
 5270            ignore_debounce,
 5271            cx,
 5272        ) {
 5273            self.splice_inlays(&to_remove, to_insert, cx);
 5274        }
 5275    }
 5276
 5277    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5278        self.display_map
 5279            .read(cx)
 5280            .current_inlays()
 5281            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5282            .cloned()
 5283            .collect()
 5284    }
 5285
 5286    pub fn visible_excerpts(
 5287        &self,
 5288        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5289        cx: &mut Context<Editor>,
 5290    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5291        let Some(project) = self.project() else {
 5292            return HashMap::default();
 5293        };
 5294        let project = project.read(cx);
 5295        let multi_buffer = self.buffer().read(cx);
 5296        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5297        let multi_buffer_visible_start = self
 5298            .scroll_manager
 5299            .anchor()
 5300            .anchor
 5301            .to_point(&multi_buffer_snapshot);
 5302        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5303            multi_buffer_visible_start
 5304                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5305            Bias::Left,
 5306        );
 5307        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5308        multi_buffer_snapshot
 5309            .range_to_buffer_ranges(multi_buffer_visible_range)
 5310            .into_iter()
 5311            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5312            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5313                let buffer_file = project::File::from_dyn(buffer.file())?;
 5314                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5315                let worktree_entry = buffer_worktree
 5316                    .read(cx)
 5317                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5318                if worktree_entry.is_ignored {
 5319                    return None;
 5320                }
 5321
 5322                let language = buffer.language()?;
 5323                if let Some(restrict_to_languages) = restrict_to_languages
 5324                    && !restrict_to_languages.contains(language)
 5325                {
 5326                    return None;
 5327                }
 5328                Some((
 5329                    excerpt_id,
 5330                    (
 5331                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5332                        buffer.version().clone(),
 5333                        excerpt_visible_range,
 5334                    ),
 5335                ))
 5336            })
 5337            .collect()
 5338    }
 5339
 5340    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5341        TextLayoutDetails {
 5342            text_system: window.text_system().clone(),
 5343            editor_style: self.style.clone().unwrap(),
 5344            rem_size: window.rem_size(),
 5345            scroll_anchor: self.scroll_manager.anchor(),
 5346            visible_rows: self.visible_line_count(),
 5347            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5348        }
 5349    }
 5350
 5351    pub fn splice_inlays(
 5352        &self,
 5353        to_remove: &[InlayId],
 5354        to_insert: Vec<Inlay>,
 5355        cx: &mut Context<Self>,
 5356    ) {
 5357        self.display_map.update(cx, |display_map, cx| {
 5358            display_map.splice_inlays(to_remove, to_insert, cx)
 5359        });
 5360        cx.notify();
 5361    }
 5362
 5363    fn trigger_on_type_formatting(
 5364        &self,
 5365        input: String,
 5366        window: &mut Window,
 5367        cx: &mut Context<Self>,
 5368    ) -> Option<Task<Result<()>>> {
 5369        if input.len() != 1 {
 5370            return None;
 5371        }
 5372
 5373        let project = self.project()?;
 5374        let position = self.selections.newest_anchor().head();
 5375        let (buffer, buffer_position) = self
 5376            .buffer
 5377            .read(cx)
 5378            .text_anchor_for_position(position, cx)?;
 5379
 5380        let settings = language_settings::language_settings(
 5381            buffer
 5382                .read(cx)
 5383                .language_at(buffer_position)
 5384                .map(|l| l.name()),
 5385            buffer.read(cx).file(),
 5386            cx,
 5387        );
 5388        if !settings.use_on_type_format {
 5389            return None;
 5390        }
 5391
 5392        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5393        // hence we do LSP request & edit on host side only — add formats to host's history.
 5394        let push_to_lsp_host_history = true;
 5395        // If this is not the host, append its history with new edits.
 5396        let push_to_client_history = project.read(cx).is_via_collab();
 5397
 5398        let on_type_formatting = project.update(cx, |project, cx| {
 5399            project.on_type_format(
 5400                buffer.clone(),
 5401                buffer_position,
 5402                input,
 5403                push_to_lsp_host_history,
 5404                cx,
 5405            )
 5406        });
 5407        Some(cx.spawn_in(window, async move |editor, cx| {
 5408            if let Some(transaction) = on_type_formatting.await? {
 5409                if push_to_client_history {
 5410                    buffer
 5411                        .update(cx, |buffer, _| {
 5412                            buffer.push_transaction(transaction, Instant::now());
 5413                            buffer.finalize_last_transaction();
 5414                        })
 5415                        .ok();
 5416                }
 5417                editor.update(cx, |editor, cx| {
 5418                    editor.refresh_document_highlights(cx);
 5419                })?;
 5420            }
 5421            Ok(())
 5422        }))
 5423    }
 5424
 5425    pub fn show_word_completions(
 5426        &mut self,
 5427        _: &ShowWordCompletions,
 5428        window: &mut Window,
 5429        cx: &mut Context<Self>,
 5430    ) {
 5431        self.open_or_update_completions_menu(
 5432            Some(CompletionsMenuSource::Words {
 5433                ignore_threshold: true,
 5434            }),
 5435            None,
 5436            window,
 5437            cx,
 5438        );
 5439    }
 5440
 5441    pub fn show_completions(
 5442        &mut self,
 5443        options: &ShowCompletions,
 5444        window: &mut Window,
 5445        cx: &mut Context<Self>,
 5446    ) {
 5447        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5448    }
 5449
 5450    fn open_or_update_completions_menu(
 5451        &mut self,
 5452        requested_source: Option<CompletionsMenuSource>,
 5453        trigger: Option<&str>,
 5454        window: &mut Window,
 5455        cx: &mut Context<Self>,
 5456    ) {
 5457        if self.pending_rename.is_some() {
 5458            return;
 5459        }
 5460
 5461        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5462
 5463        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5464        // inserted and selected. To handle that case, the start of the selection is used so that
 5465        // the menu starts with all choices.
 5466        let position = self
 5467            .selections
 5468            .newest_anchor()
 5469            .start
 5470            .bias_right(&multibuffer_snapshot);
 5471        if position.diff_base_anchor.is_some() {
 5472            return;
 5473        }
 5474        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5475        let Some(buffer) = buffer_position
 5476            .buffer_id
 5477            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5478        else {
 5479            return;
 5480        };
 5481        let buffer_snapshot = buffer.read(cx).snapshot();
 5482
 5483        let query: Option<Arc<String>> =
 5484            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5485                .map(|query| query.into());
 5486
 5487        drop(multibuffer_snapshot);
 5488
 5489        // Hide the current completions menu when query is empty. Without this, cached
 5490        // completions from before the trigger char may be reused (#32774).
 5491        if query.is_none() {
 5492            let menu_is_open = matches!(
 5493                self.context_menu.borrow().as_ref(),
 5494                Some(CodeContextMenu::Completions(_))
 5495            );
 5496            if menu_is_open {
 5497                self.hide_context_menu(window, cx);
 5498            }
 5499        }
 5500
 5501        let mut ignore_word_threshold = false;
 5502        let provider = match requested_source {
 5503            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5504            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5505                ignore_word_threshold = ignore_threshold;
 5506                None
 5507            }
 5508            Some(CompletionsMenuSource::SnippetChoices) => {
 5509                log::error!("bug: SnippetChoices requested_source is not handled");
 5510                None
 5511            }
 5512        };
 5513
 5514        let sort_completions = provider
 5515            .as_ref()
 5516            .is_some_and(|provider| provider.sort_completions());
 5517
 5518        let filter_completions = provider
 5519            .as_ref()
 5520            .is_none_or(|provider| provider.filter_completions());
 5521
 5522        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5523            if filter_completions {
 5524                menu.filter(query.clone(), provider.clone(), window, cx);
 5525            }
 5526            // When `is_incomplete` is false, no need to re-query completions when the current query
 5527            // is a suffix of the initial query.
 5528            if !menu.is_incomplete {
 5529                // If the new query is a suffix of the old query (typing more characters) and
 5530                // the previous result was complete, the existing completions can be filtered.
 5531                //
 5532                // Note that this is always true for snippet completions.
 5533                let query_matches = match (&menu.initial_query, &query) {
 5534                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5535                    (None, _) => true,
 5536                    _ => false,
 5537                };
 5538                if query_matches {
 5539                    let position_matches = if menu.initial_position == position {
 5540                        true
 5541                    } else {
 5542                        let snapshot = self.buffer.read(cx).read(cx);
 5543                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5544                    };
 5545                    if position_matches {
 5546                        return;
 5547                    }
 5548                }
 5549            }
 5550        };
 5551
 5552        let trigger_kind = match trigger {
 5553            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5554                CompletionTriggerKind::TRIGGER_CHARACTER
 5555            }
 5556            _ => CompletionTriggerKind::INVOKED,
 5557        };
 5558        let completion_context = CompletionContext {
 5559            trigger_character: trigger.and_then(|trigger| {
 5560                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5561                    Some(String::from(trigger))
 5562                } else {
 5563                    None
 5564                }
 5565            }),
 5566            trigger_kind,
 5567        };
 5568
 5569        let Anchor {
 5570            excerpt_id: buffer_excerpt_id,
 5571            text_anchor: buffer_position,
 5572            ..
 5573        } = buffer_position;
 5574
 5575        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5576            buffer_snapshot.surrounding_word(buffer_position, None)
 5577        {
 5578            let word_to_exclude = buffer_snapshot
 5579                .text_for_range(word_range.clone())
 5580                .collect::<String>();
 5581            (
 5582                buffer_snapshot.anchor_before(word_range.start)
 5583                    ..buffer_snapshot.anchor_after(buffer_position),
 5584                Some(word_to_exclude),
 5585            )
 5586        } else {
 5587            (buffer_position..buffer_position, None)
 5588        };
 5589
 5590        let language = buffer_snapshot
 5591            .language_at(buffer_position)
 5592            .map(|language| language.name());
 5593
 5594        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5595            .completions
 5596            .clone();
 5597
 5598        let show_completion_documentation = buffer_snapshot
 5599            .settings_at(buffer_position, cx)
 5600            .show_completion_documentation;
 5601
 5602        // The document can be large, so stay in reasonable bounds when searching for words,
 5603        // otherwise completion pop-up might be slow to appear.
 5604        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5605        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5606        let min_word_search = buffer_snapshot.clip_point(
 5607            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5608            Bias::Left,
 5609        );
 5610        let max_word_search = buffer_snapshot.clip_point(
 5611            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5612            Bias::Right,
 5613        );
 5614        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5615            ..buffer_snapshot.point_to_offset(max_word_search);
 5616
 5617        let skip_digits = query
 5618            .as_ref()
 5619            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5620
 5621        let omit_word_completions = !self.word_completions_enabled
 5622            || (!ignore_word_threshold
 5623                && match &query {
 5624                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5625                    None => completion_settings.words_min_length != 0,
 5626                });
 5627
 5628        let (mut words, provider_responses) = match &provider {
 5629            Some(provider) => {
 5630                let provider_responses = provider.completions(
 5631                    buffer_excerpt_id,
 5632                    &buffer,
 5633                    buffer_position,
 5634                    completion_context,
 5635                    window,
 5636                    cx,
 5637                );
 5638
 5639                let words = match (omit_word_completions, completion_settings.words) {
 5640                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5641                        Task::ready(BTreeMap::default())
 5642                    }
 5643                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5644                        .background_spawn(async move {
 5645                            buffer_snapshot.words_in_range(WordsQuery {
 5646                                fuzzy_contents: None,
 5647                                range: word_search_range,
 5648                                skip_digits,
 5649                            })
 5650                        }),
 5651                };
 5652
 5653                (words, provider_responses)
 5654            }
 5655            None => {
 5656                let words = if omit_word_completions {
 5657                    Task::ready(BTreeMap::default())
 5658                } else {
 5659                    cx.background_spawn(async move {
 5660                        buffer_snapshot.words_in_range(WordsQuery {
 5661                            fuzzy_contents: None,
 5662                            range: word_search_range,
 5663                            skip_digits,
 5664                        })
 5665                    })
 5666                };
 5667                (words, Task::ready(Ok(Vec::new())))
 5668            }
 5669        };
 5670
 5671        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5672
 5673        let id = post_inc(&mut self.next_completion_id);
 5674        let task = cx.spawn_in(window, async move |editor, cx| {
 5675            let Ok(()) = editor.update(cx, |this, _| {
 5676                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5677            }) else {
 5678                return;
 5679            };
 5680
 5681            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5682            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5683            let mut completions = Vec::new();
 5684            let mut is_incomplete = false;
 5685            let mut display_options: Option<CompletionDisplayOptions> = None;
 5686            if let Some(provider_responses) = provider_responses.await.log_err()
 5687                && !provider_responses.is_empty()
 5688            {
 5689                for response in provider_responses {
 5690                    completions.extend(response.completions);
 5691                    is_incomplete = is_incomplete || response.is_incomplete;
 5692                    match display_options.as_mut() {
 5693                        None => {
 5694                            display_options = Some(response.display_options);
 5695                        }
 5696                        Some(options) => options.merge(&response.display_options),
 5697                    }
 5698                }
 5699                if completion_settings.words == WordsCompletionMode::Fallback {
 5700                    words = Task::ready(BTreeMap::default());
 5701                }
 5702            }
 5703            let display_options = display_options.unwrap_or_default();
 5704
 5705            let mut words = words.await;
 5706            if let Some(word_to_exclude) = &word_to_exclude {
 5707                words.remove(word_to_exclude);
 5708            }
 5709            for lsp_completion in &completions {
 5710                words.remove(&lsp_completion.new_text);
 5711            }
 5712            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5713                replace_range: word_replace_range.clone(),
 5714                new_text: word.clone(),
 5715                label: CodeLabel::plain(word, None),
 5716                icon_path: None,
 5717                documentation: None,
 5718                source: CompletionSource::BufferWord {
 5719                    word_range,
 5720                    resolved: false,
 5721                },
 5722                insert_text_mode: Some(InsertTextMode::AS_IS),
 5723                confirm: None,
 5724            }));
 5725
 5726            let menu = if completions.is_empty() {
 5727                None
 5728            } else {
 5729                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5730                    let languages = editor
 5731                        .workspace
 5732                        .as_ref()
 5733                        .and_then(|(workspace, _)| workspace.upgrade())
 5734                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5735                    let menu = CompletionsMenu::new(
 5736                        id,
 5737                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5738                        sort_completions,
 5739                        show_completion_documentation,
 5740                        position,
 5741                        query.clone(),
 5742                        is_incomplete,
 5743                        buffer.clone(),
 5744                        completions.into(),
 5745                        display_options,
 5746                        snippet_sort_order,
 5747                        languages,
 5748                        language,
 5749                        cx,
 5750                    );
 5751
 5752                    let query = if filter_completions { query } else { None };
 5753                    let matches_task = if let Some(query) = query {
 5754                        menu.do_async_filtering(query, cx)
 5755                    } else {
 5756                        Task::ready(menu.unfiltered_matches())
 5757                    };
 5758                    (menu, matches_task)
 5759                }) else {
 5760                    return;
 5761                };
 5762
 5763                let matches = matches_task.await;
 5764
 5765                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5766                    // Newer menu already set, so exit.
 5767                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5768                        editor.context_menu.borrow().as_ref()
 5769                        && prev_menu.id > id
 5770                    {
 5771                        return;
 5772                    };
 5773
 5774                    // Only valid to take prev_menu because it the new menu is immediately set
 5775                    // below, or the menu is hidden.
 5776                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5777                        editor.context_menu.borrow_mut().take()
 5778                    {
 5779                        let position_matches =
 5780                            if prev_menu.initial_position == menu.initial_position {
 5781                                true
 5782                            } else {
 5783                                let snapshot = editor.buffer.read(cx).read(cx);
 5784                                prev_menu.initial_position.to_offset(&snapshot)
 5785                                    == menu.initial_position.to_offset(&snapshot)
 5786                            };
 5787                        if position_matches {
 5788                            // Preserve markdown cache before `set_filter_results` because it will
 5789                            // try to populate the documentation cache.
 5790                            menu.preserve_markdown_cache(prev_menu);
 5791                        }
 5792                    };
 5793
 5794                    menu.set_filter_results(matches, provider, window, cx);
 5795                }) else {
 5796                    return;
 5797                };
 5798
 5799                menu.visible().then_some(menu)
 5800            };
 5801
 5802            editor
 5803                .update_in(cx, |editor, window, cx| {
 5804                    if editor.focus_handle.is_focused(window)
 5805                        && let Some(menu) = menu
 5806                    {
 5807                        *editor.context_menu.borrow_mut() =
 5808                            Some(CodeContextMenu::Completions(menu));
 5809
 5810                        crate::hover_popover::hide_hover(editor, cx);
 5811                        if editor.show_edit_predictions_in_menu() {
 5812                            editor.update_visible_edit_prediction(window, cx);
 5813                        } else {
 5814                            editor.discard_edit_prediction(false, cx);
 5815                        }
 5816
 5817                        cx.notify();
 5818                        return;
 5819                    }
 5820
 5821                    if editor.completion_tasks.len() <= 1 {
 5822                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5823                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5824                        // If it was already hidden and we don't show edit predictions in the menu,
 5825                        // we should also show the edit prediction when available.
 5826                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5827                            editor.update_visible_edit_prediction(window, cx);
 5828                        }
 5829                    }
 5830                })
 5831                .ok();
 5832        });
 5833
 5834        self.completion_tasks.push((id, task));
 5835    }
 5836
 5837    #[cfg(feature = "test-support")]
 5838    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5839        let menu = self.context_menu.borrow();
 5840        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5841            let completions = menu.completions.borrow();
 5842            Some(completions.to_vec())
 5843        } else {
 5844            None
 5845        }
 5846    }
 5847
 5848    pub fn with_completions_menu_matching_id<R>(
 5849        &self,
 5850        id: CompletionId,
 5851        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5852    ) -> R {
 5853        let mut context_menu = self.context_menu.borrow_mut();
 5854        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5855            return f(None);
 5856        };
 5857        if completions_menu.id != id {
 5858            return f(None);
 5859        }
 5860        f(Some(completions_menu))
 5861    }
 5862
 5863    pub fn confirm_completion(
 5864        &mut self,
 5865        action: &ConfirmCompletion,
 5866        window: &mut Window,
 5867        cx: &mut Context<Self>,
 5868    ) -> Option<Task<Result<()>>> {
 5869        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5870        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5871    }
 5872
 5873    pub fn confirm_completion_insert(
 5874        &mut self,
 5875        _: &ConfirmCompletionInsert,
 5876        window: &mut Window,
 5877        cx: &mut Context<Self>,
 5878    ) -> Option<Task<Result<()>>> {
 5879        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5880        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5881    }
 5882
 5883    pub fn confirm_completion_replace(
 5884        &mut self,
 5885        _: &ConfirmCompletionReplace,
 5886        window: &mut Window,
 5887        cx: &mut Context<Self>,
 5888    ) -> Option<Task<Result<()>>> {
 5889        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5890        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5891    }
 5892
 5893    pub fn compose_completion(
 5894        &mut self,
 5895        action: &ComposeCompletion,
 5896        window: &mut Window,
 5897        cx: &mut Context<Self>,
 5898    ) -> Option<Task<Result<()>>> {
 5899        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5900        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5901    }
 5902
 5903    fn do_completion(
 5904        &mut self,
 5905        item_ix: Option<usize>,
 5906        intent: CompletionIntent,
 5907        window: &mut Window,
 5908        cx: &mut Context<Editor>,
 5909    ) -> Option<Task<Result<()>>> {
 5910        use language::ToOffset as _;
 5911
 5912        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5913        else {
 5914            return None;
 5915        };
 5916
 5917        let candidate_id = {
 5918            let entries = completions_menu.entries.borrow();
 5919            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5920            if self.show_edit_predictions_in_menu() {
 5921                self.discard_edit_prediction(true, cx);
 5922            }
 5923            mat.candidate_id
 5924        };
 5925
 5926        let completion = completions_menu
 5927            .completions
 5928            .borrow()
 5929            .get(candidate_id)?
 5930            .clone();
 5931        cx.stop_propagation();
 5932
 5933        let buffer_handle = completions_menu.buffer.clone();
 5934
 5935        let CompletionEdit {
 5936            new_text,
 5937            snippet,
 5938            replace_range,
 5939        } = process_completion_for_edit(
 5940            &completion,
 5941            intent,
 5942            &buffer_handle,
 5943            &completions_menu.initial_position.text_anchor,
 5944            cx,
 5945        );
 5946
 5947        let buffer = buffer_handle.read(cx);
 5948        let snapshot = self.buffer.read(cx).snapshot(cx);
 5949        let newest_anchor = self.selections.newest_anchor();
 5950        let replace_range_multibuffer = {
 5951            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5952            let multibuffer_anchor = snapshot
 5953                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5954                .unwrap()
 5955                ..snapshot
 5956                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5957                    .unwrap();
 5958            multibuffer_anchor.start.to_offset(&snapshot)
 5959                ..multibuffer_anchor.end.to_offset(&snapshot)
 5960        };
 5961        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5962            return None;
 5963        }
 5964
 5965        let old_text = buffer
 5966            .text_for_range(replace_range.clone())
 5967            .collect::<String>();
 5968        let lookbehind = newest_anchor
 5969            .start
 5970            .text_anchor
 5971            .to_offset(buffer)
 5972            .saturating_sub(replace_range.start);
 5973        let lookahead = replace_range
 5974            .end
 5975            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5976        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5977        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5978
 5979        let selections = self.selections.all::<usize>(cx);
 5980        let mut ranges = Vec::new();
 5981        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5982
 5983        for selection in &selections {
 5984            let range = if selection.id == newest_anchor.id {
 5985                replace_range_multibuffer.clone()
 5986            } else {
 5987                let mut range = selection.range();
 5988
 5989                // if prefix is present, don't duplicate it
 5990                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5991                    range.start = range.start.saturating_sub(lookbehind);
 5992
 5993                    // if suffix is also present, mimic the newest cursor and replace it
 5994                    if selection.id != newest_anchor.id
 5995                        && snapshot.contains_str_at(range.end, suffix)
 5996                    {
 5997                        range.end += lookahead;
 5998                    }
 5999                }
 6000                range
 6001            };
 6002
 6003            ranges.push(range.clone());
 6004
 6005            if !self.linked_edit_ranges.is_empty() {
 6006                let start_anchor = snapshot.anchor_before(range.start);
 6007                let end_anchor = snapshot.anchor_after(range.end);
 6008                if let Some(ranges) = self
 6009                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6010                {
 6011                    for (buffer, edits) in ranges {
 6012                        linked_edits
 6013                            .entry(buffer.clone())
 6014                            .or_default()
 6015                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6016                    }
 6017                }
 6018            }
 6019        }
 6020
 6021        let common_prefix_len = old_text
 6022            .chars()
 6023            .zip(new_text.chars())
 6024            .take_while(|(a, b)| a == b)
 6025            .map(|(a, _)| a.len_utf8())
 6026            .sum::<usize>();
 6027
 6028        cx.emit(EditorEvent::InputHandled {
 6029            utf16_range_to_replace: None,
 6030            text: new_text[common_prefix_len..].into(),
 6031        });
 6032
 6033        self.transact(window, cx, |editor, window, cx| {
 6034            if let Some(mut snippet) = snippet {
 6035                snippet.text = new_text.to_string();
 6036                editor
 6037                    .insert_snippet(&ranges, snippet, window, cx)
 6038                    .log_err();
 6039            } else {
 6040                editor.buffer.update(cx, |multi_buffer, cx| {
 6041                    let auto_indent = match completion.insert_text_mode {
 6042                        Some(InsertTextMode::AS_IS) => None,
 6043                        _ => editor.autoindent_mode.clone(),
 6044                    };
 6045                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6046                    multi_buffer.edit(edits, auto_indent, cx);
 6047                });
 6048            }
 6049            for (buffer, edits) in linked_edits {
 6050                buffer.update(cx, |buffer, cx| {
 6051                    let snapshot = buffer.snapshot();
 6052                    let edits = edits
 6053                        .into_iter()
 6054                        .map(|(range, text)| {
 6055                            use text::ToPoint as TP;
 6056                            let end_point = TP::to_point(&range.end, &snapshot);
 6057                            let start_point = TP::to_point(&range.start, &snapshot);
 6058                            (start_point..end_point, text)
 6059                        })
 6060                        .sorted_by_key(|(range, _)| range.start);
 6061                    buffer.edit(edits, None, cx);
 6062                })
 6063            }
 6064
 6065            editor.refresh_edit_prediction(true, false, window, cx);
 6066        });
 6067        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6068
 6069        let show_new_completions_on_confirm = completion
 6070            .confirm
 6071            .as_ref()
 6072            .is_some_and(|confirm| confirm(intent, window, cx));
 6073        if show_new_completions_on_confirm {
 6074            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6075        }
 6076
 6077        let provider = self.completion_provider.as_ref()?;
 6078        drop(completion);
 6079        let apply_edits = provider.apply_additional_edits_for_completion(
 6080            buffer_handle,
 6081            completions_menu.completions.clone(),
 6082            candidate_id,
 6083            true,
 6084            cx,
 6085        );
 6086
 6087        let editor_settings = EditorSettings::get_global(cx);
 6088        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6089            // After the code completion is finished, users often want to know what signatures are needed.
 6090            // so we should automatically call signature_help
 6091            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6092        }
 6093
 6094        Some(cx.foreground_executor().spawn(async move {
 6095            apply_edits.await?;
 6096            Ok(())
 6097        }))
 6098    }
 6099
 6100    pub fn toggle_code_actions(
 6101        &mut self,
 6102        action: &ToggleCodeActions,
 6103        window: &mut Window,
 6104        cx: &mut Context<Self>,
 6105    ) {
 6106        let quick_launch = action.quick_launch;
 6107        let mut context_menu = self.context_menu.borrow_mut();
 6108        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6109            if code_actions.deployed_from == action.deployed_from {
 6110                // Toggle if we're selecting the same one
 6111                *context_menu = None;
 6112                cx.notify();
 6113                return;
 6114            } else {
 6115                // Otherwise, clear it and start a new one
 6116                *context_menu = None;
 6117                cx.notify();
 6118            }
 6119        }
 6120        drop(context_menu);
 6121        let snapshot = self.snapshot(window, cx);
 6122        let deployed_from = action.deployed_from.clone();
 6123        let action = action.clone();
 6124        self.completion_tasks.clear();
 6125        self.discard_edit_prediction(false, cx);
 6126
 6127        let multibuffer_point = match &action.deployed_from {
 6128            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6129                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6130            }
 6131            _ => self.selections.newest::<Point>(cx).head(),
 6132        };
 6133        let Some((buffer, buffer_row)) = snapshot
 6134            .buffer_snapshot
 6135            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6136            .and_then(|(buffer_snapshot, range)| {
 6137                self.buffer()
 6138                    .read(cx)
 6139                    .buffer(buffer_snapshot.remote_id())
 6140                    .map(|buffer| (buffer, range.start.row))
 6141            })
 6142        else {
 6143            return;
 6144        };
 6145        let buffer_id = buffer.read(cx).remote_id();
 6146        let tasks = self
 6147            .tasks
 6148            .get(&(buffer_id, buffer_row))
 6149            .map(|t| Arc::new(t.to_owned()));
 6150
 6151        if !self.focus_handle.is_focused(window) {
 6152            return;
 6153        }
 6154        let project = self.project.clone();
 6155
 6156        let code_actions_task = match deployed_from {
 6157            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6158            _ => self.code_actions(buffer_row, window, cx),
 6159        };
 6160
 6161        let runnable_task = match deployed_from {
 6162            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6163            _ => {
 6164                let mut task_context_task = Task::ready(None);
 6165                if let Some(tasks) = &tasks
 6166                    && let Some(project) = project
 6167                {
 6168                    task_context_task =
 6169                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6170                }
 6171
 6172                cx.spawn_in(window, {
 6173                    let buffer = buffer.clone();
 6174                    async move |editor, cx| {
 6175                        let task_context = task_context_task.await;
 6176
 6177                        let resolved_tasks =
 6178                            tasks
 6179                                .zip(task_context.clone())
 6180                                .map(|(tasks, task_context)| ResolvedTasks {
 6181                                    templates: tasks.resolve(&task_context).collect(),
 6182                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6183                                        multibuffer_point.row,
 6184                                        tasks.column,
 6185                                    )),
 6186                                });
 6187                        let debug_scenarios = editor
 6188                            .update(cx, |editor, cx| {
 6189                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6190                            })?
 6191                            .await;
 6192                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6193                    }
 6194                })
 6195            }
 6196        };
 6197
 6198        cx.spawn_in(window, async move |editor, cx| {
 6199            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6200            let code_actions = code_actions_task.await;
 6201            let spawn_straight_away = quick_launch
 6202                && resolved_tasks
 6203                    .as_ref()
 6204                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6205                && code_actions
 6206                    .as_ref()
 6207                    .is_none_or(|actions| actions.is_empty())
 6208                && debug_scenarios.is_empty();
 6209
 6210            editor.update_in(cx, |editor, window, cx| {
 6211                crate::hover_popover::hide_hover(editor, cx);
 6212                let actions = CodeActionContents::new(
 6213                    resolved_tasks,
 6214                    code_actions,
 6215                    debug_scenarios,
 6216                    task_context.unwrap_or_default(),
 6217                );
 6218
 6219                // Don't show the menu if there are no actions available
 6220                if actions.is_empty() {
 6221                    cx.notify();
 6222                    return Task::ready(Ok(()));
 6223                }
 6224
 6225                *editor.context_menu.borrow_mut() =
 6226                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6227                        buffer,
 6228                        actions,
 6229                        selected_item: Default::default(),
 6230                        scroll_handle: UniformListScrollHandle::default(),
 6231                        deployed_from,
 6232                    }));
 6233                cx.notify();
 6234                if spawn_straight_away
 6235                    && let Some(task) = editor.confirm_code_action(
 6236                        &ConfirmCodeAction { item_ix: Some(0) },
 6237                        window,
 6238                        cx,
 6239                    )
 6240                {
 6241                    return task;
 6242                }
 6243
 6244                Task::ready(Ok(()))
 6245            })
 6246        })
 6247        .detach_and_log_err(cx);
 6248    }
 6249
 6250    fn debug_scenarios(
 6251        &mut self,
 6252        resolved_tasks: &Option<ResolvedTasks>,
 6253        buffer: &Entity<Buffer>,
 6254        cx: &mut App,
 6255    ) -> Task<Vec<task::DebugScenario>> {
 6256        maybe!({
 6257            let project = self.project()?;
 6258            let dap_store = project.read(cx).dap_store();
 6259            let mut scenarios = vec![];
 6260            let resolved_tasks = resolved_tasks.as_ref()?;
 6261            let buffer = buffer.read(cx);
 6262            let language = buffer.language()?;
 6263            let file = buffer.file();
 6264            let debug_adapter = language_settings(language.name().into(), file, cx)
 6265                .debuggers
 6266                .first()
 6267                .map(SharedString::from)
 6268                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6269
 6270            dap_store.update(cx, |dap_store, cx| {
 6271                for (_, task) in &resolved_tasks.templates {
 6272                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6273                        task.original_task().clone(),
 6274                        debug_adapter.clone().into(),
 6275                        task.display_label().to_owned().into(),
 6276                        cx,
 6277                    );
 6278                    scenarios.push(maybe_scenario);
 6279                }
 6280            });
 6281            Some(cx.background_spawn(async move {
 6282                futures::future::join_all(scenarios)
 6283                    .await
 6284                    .into_iter()
 6285                    .flatten()
 6286                    .collect::<Vec<_>>()
 6287            }))
 6288        })
 6289        .unwrap_or_else(|| Task::ready(vec![]))
 6290    }
 6291
 6292    fn code_actions(
 6293        &mut self,
 6294        buffer_row: u32,
 6295        window: &mut Window,
 6296        cx: &mut Context<Self>,
 6297    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6298        let mut task = self.code_actions_task.take();
 6299        cx.spawn_in(window, async move |editor, cx| {
 6300            while let Some(prev_task) = task {
 6301                prev_task.await.log_err();
 6302                task = editor
 6303                    .update(cx, |this, _| this.code_actions_task.take())
 6304                    .ok()?;
 6305            }
 6306
 6307            editor
 6308                .update(cx, |editor, cx| {
 6309                    editor
 6310                        .available_code_actions
 6311                        .clone()
 6312                        .and_then(|(location, code_actions)| {
 6313                            let snapshot = location.buffer.read(cx).snapshot();
 6314                            let point_range = location.range.to_point(&snapshot);
 6315                            let point_range = point_range.start.row..=point_range.end.row;
 6316                            if point_range.contains(&buffer_row) {
 6317                                Some(code_actions)
 6318                            } else {
 6319                                None
 6320                            }
 6321                        })
 6322                })
 6323                .ok()
 6324                .flatten()
 6325        })
 6326    }
 6327
 6328    pub fn confirm_code_action(
 6329        &mut self,
 6330        action: &ConfirmCodeAction,
 6331        window: &mut Window,
 6332        cx: &mut Context<Self>,
 6333    ) -> Option<Task<Result<()>>> {
 6334        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6335
 6336        let actions_menu =
 6337            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6338                menu
 6339            } else {
 6340                return None;
 6341            };
 6342
 6343        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6344        let action = actions_menu.actions.get(action_ix)?;
 6345        let title = action.label();
 6346        let buffer = actions_menu.buffer;
 6347        let workspace = self.workspace()?;
 6348
 6349        match action {
 6350            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6351                workspace.update(cx, |workspace, cx| {
 6352                    workspace.schedule_resolved_task(
 6353                        task_source_kind,
 6354                        resolved_task,
 6355                        false,
 6356                        window,
 6357                        cx,
 6358                    );
 6359
 6360                    Some(Task::ready(Ok(())))
 6361                })
 6362            }
 6363            CodeActionsItem::CodeAction {
 6364                excerpt_id,
 6365                action,
 6366                provider,
 6367            } => {
 6368                let apply_code_action =
 6369                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6370                let workspace = workspace.downgrade();
 6371                Some(cx.spawn_in(window, async move |editor, cx| {
 6372                    let project_transaction = apply_code_action.await?;
 6373                    Self::open_project_transaction(
 6374                        &editor,
 6375                        workspace,
 6376                        project_transaction,
 6377                        title,
 6378                        cx,
 6379                    )
 6380                    .await
 6381                }))
 6382            }
 6383            CodeActionsItem::DebugScenario(scenario) => {
 6384                let context = actions_menu.actions.context;
 6385
 6386                workspace.update(cx, |workspace, cx| {
 6387                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6388                    workspace.start_debug_session(
 6389                        scenario,
 6390                        context,
 6391                        Some(buffer),
 6392                        None,
 6393                        window,
 6394                        cx,
 6395                    );
 6396                });
 6397                Some(Task::ready(Ok(())))
 6398            }
 6399        }
 6400    }
 6401
 6402    pub async fn open_project_transaction(
 6403        editor: &WeakEntity<Editor>,
 6404        workspace: WeakEntity<Workspace>,
 6405        transaction: ProjectTransaction,
 6406        title: String,
 6407        cx: &mut AsyncWindowContext,
 6408    ) -> Result<()> {
 6409        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6410        cx.update(|_, cx| {
 6411            entries.sort_unstable_by_key(|(buffer, _)| {
 6412                buffer.read(cx).file().map(|f| f.path().clone())
 6413            });
 6414        })?;
 6415
 6416        // If the project transaction's edits are all contained within this editor, then
 6417        // avoid opening a new editor to display them.
 6418
 6419        if let Some((buffer, transaction)) = entries.first() {
 6420            if entries.len() == 1 {
 6421                let excerpt = editor.update(cx, |editor, cx| {
 6422                    editor
 6423                        .buffer()
 6424                        .read(cx)
 6425                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6426                })?;
 6427                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6428                    && excerpted_buffer == *buffer
 6429                {
 6430                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6431                        let excerpt_range = excerpt_range.to_offset(buffer);
 6432                        buffer
 6433                            .edited_ranges_for_transaction::<usize>(transaction)
 6434                            .all(|range| {
 6435                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6436                            })
 6437                    })?;
 6438
 6439                    if all_edits_within_excerpt {
 6440                        return Ok(());
 6441                    }
 6442                }
 6443            }
 6444        } else {
 6445            return Ok(());
 6446        }
 6447
 6448        let mut ranges_to_highlight = Vec::new();
 6449        let excerpt_buffer = cx.new(|cx| {
 6450            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6451            for (buffer_handle, transaction) in &entries {
 6452                let edited_ranges = buffer_handle
 6453                    .read(cx)
 6454                    .edited_ranges_for_transaction::<Point>(transaction)
 6455                    .collect::<Vec<_>>();
 6456                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6457                    PathKey::for_buffer(buffer_handle, cx),
 6458                    buffer_handle.clone(),
 6459                    edited_ranges,
 6460                    multibuffer_context_lines(cx),
 6461                    cx,
 6462                );
 6463
 6464                ranges_to_highlight.extend(ranges);
 6465            }
 6466            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6467            multibuffer
 6468        })?;
 6469
 6470        workspace.update_in(cx, |workspace, window, cx| {
 6471            let project = workspace.project().clone();
 6472            let editor =
 6473                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6474            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6475            editor.update(cx, |editor, cx| {
 6476                editor.highlight_background::<Self>(
 6477                    &ranges_to_highlight,
 6478                    |theme| theme.colors().editor_highlighted_line_background,
 6479                    cx,
 6480                );
 6481            });
 6482        })?;
 6483
 6484        Ok(())
 6485    }
 6486
 6487    pub fn clear_code_action_providers(&mut self) {
 6488        self.code_action_providers.clear();
 6489        self.available_code_actions.take();
 6490    }
 6491
 6492    pub fn add_code_action_provider(
 6493        &mut self,
 6494        provider: Rc<dyn CodeActionProvider>,
 6495        window: &mut Window,
 6496        cx: &mut Context<Self>,
 6497    ) {
 6498        if self
 6499            .code_action_providers
 6500            .iter()
 6501            .any(|existing_provider| existing_provider.id() == provider.id())
 6502        {
 6503            return;
 6504        }
 6505
 6506        self.code_action_providers.push(provider);
 6507        self.refresh_code_actions(window, cx);
 6508    }
 6509
 6510    pub fn remove_code_action_provider(
 6511        &mut self,
 6512        id: Arc<str>,
 6513        window: &mut Window,
 6514        cx: &mut Context<Self>,
 6515    ) {
 6516        self.code_action_providers
 6517            .retain(|provider| provider.id() != id);
 6518        self.refresh_code_actions(window, cx);
 6519    }
 6520
 6521    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6522        !self.code_action_providers.is_empty()
 6523            && EditorSettings::get_global(cx).toolbar.code_actions
 6524    }
 6525
 6526    pub fn has_available_code_actions(&self) -> bool {
 6527        self.available_code_actions
 6528            .as_ref()
 6529            .is_some_and(|(_, actions)| !actions.is_empty())
 6530    }
 6531
 6532    fn render_inline_code_actions(
 6533        &self,
 6534        icon_size: ui::IconSize,
 6535        display_row: DisplayRow,
 6536        is_active: bool,
 6537        cx: &mut Context<Self>,
 6538    ) -> AnyElement {
 6539        let show_tooltip = !self.context_menu_visible();
 6540        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6541            .icon_size(icon_size)
 6542            .shape(ui::IconButtonShape::Square)
 6543            .icon_color(ui::Color::Hidden)
 6544            .toggle_state(is_active)
 6545            .when(show_tooltip, |this| {
 6546                this.tooltip({
 6547                    let focus_handle = self.focus_handle.clone();
 6548                    move |window, cx| {
 6549                        Tooltip::for_action_in(
 6550                            "Toggle Code Actions",
 6551                            &ToggleCodeActions {
 6552                                deployed_from: None,
 6553                                quick_launch: false,
 6554                            },
 6555                            &focus_handle,
 6556                            window,
 6557                            cx,
 6558                        )
 6559                    }
 6560                })
 6561            })
 6562            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6563                window.focus(&editor.focus_handle(cx));
 6564                editor.toggle_code_actions(
 6565                    &crate::actions::ToggleCodeActions {
 6566                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6567                            display_row,
 6568                        )),
 6569                        quick_launch: false,
 6570                    },
 6571                    window,
 6572                    cx,
 6573                );
 6574            }))
 6575            .into_any_element()
 6576    }
 6577
 6578    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6579        &self.context_menu
 6580    }
 6581
 6582    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6583        let newest_selection = self.selections.newest_anchor().clone();
 6584        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6585        let buffer = self.buffer.read(cx);
 6586        if newest_selection.head().diff_base_anchor.is_some() {
 6587            return None;
 6588        }
 6589        let (start_buffer, start) =
 6590            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6591        let (end_buffer, end) =
 6592            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6593        if start_buffer != end_buffer {
 6594            return None;
 6595        }
 6596
 6597        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6598            cx.background_executor()
 6599                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6600                .await;
 6601
 6602            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6603                let providers = this.code_action_providers.clone();
 6604                let tasks = this
 6605                    .code_action_providers
 6606                    .iter()
 6607                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6608                    .collect::<Vec<_>>();
 6609                (providers, tasks)
 6610            })?;
 6611
 6612            let mut actions = Vec::new();
 6613            for (provider, provider_actions) in
 6614                providers.into_iter().zip(future::join_all(tasks).await)
 6615            {
 6616                if let Some(provider_actions) = provider_actions.log_err() {
 6617                    actions.extend(provider_actions.into_iter().map(|action| {
 6618                        AvailableCodeAction {
 6619                            excerpt_id: newest_selection.start.excerpt_id,
 6620                            action,
 6621                            provider: provider.clone(),
 6622                        }
 6623                    }));
 6624                }
 6625            }
 6626
 6627            this.update(cx, |this, cx| {
 6628                this.available_code_actions = if actions.is_empty() {
 6629                    None
 6630                } else {
 6631                    Some((
 6632                        Location {
 6633                            buffer: start_buffer,
 6634                            range: start..end,
 6635                        },
 6636                        actions.into(),
 6637                    ))
 6638                };
 6639                cx.notify();
 6640            })
 6641        }));
 6642        None
 6643    }
 6644
 6645    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6646        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6647            self.show_git_blame_inline = false;
 6648
 6649            self.show_git_blame_inline_delay_task =
 6650                Some(cx.spawn_in(window, async move |this, cx| {
 6651                    cx.background_executor().timer(delay).await;
 6652
 6653                    this.update(cx, |this, cx| {
 6654                        this.show_git_blame_inline = true;
 6655                        cx.notify();
 6656                    })
 6657                    .log_err();
 6658                }));
 6659        }
 6660    }
 6661
 6662    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6663        let snapshot = self.snapshot(window, cx);
 6664        let cursor = self.selections.newest::<Point>(cx).head();
 6665        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6666        else {
 6667            return;
 6668        };
 6669
 6670        let Some(blame) = self.blame.as_ref() else {
 6671            return;
 6672        };
 6673
 6674        let row_info = RowInfo {
 6675            buffer_id: Some(buffer.remote_id()),
 6676            buffer_row: Some(point.row),
 6677            ..Default::default()
 6678        };
 6679        let Some((buffer, blame_entry)) = blame
 6680            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6681            .flatten()
 6682        else {
 6683            return;
 6684        };
 6685
 6686        let anchor = self.selections.newest_anchor().head();
 6687        let position = self.to_pixel_point(anchor, &snapshot, window);
 6688        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6689            self.show_blame_popover(
 6690                buffer,
 6691                &blame_entry,
 6692                position + last_bounds.origin,
 6693                true,
 6694                cx,
 6695            );
 6696        };
 6697    }
 6698
 6699    fn show_blame_popover(
 6700        &mut self,
 6701        buffer: BufferId,
 6702        blame_entry: &BlameEntry,
 6703        position: gpui::Point<Pixels>,
 6704        ignore_timeout: bool,
 6705        cx: &mut Context<Self>,
 6706    ) {
 6707        if let Some(state) = &mut self.inline_blame_popover {
 6708            state.hide_task.take();
 6709        } else {
 6710            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6711            let blame_entry = blame_entry.clone();
 6712            let show_task = cx.spawn(async move |editor, cx| {
 6713                if !ignore_timeout {
 6714                    cx.background_executor()
 6715                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6716                        .await;
 6717                }
 6718                editor
 6719                    .update(cx, |editor, cx| {
 6720                        editor.inline_blame_popover_show_task.take();
 6721                        let Some(blame) = editor.blame.as_ref() else {
 6722                            return;
 6723                        };
 6724                        let blame = blame.read(cx);
 6725                        let details = blame.details_for_entry(buffer, &blame_entry);
 6726                        let markdown = cx.new(|cx| {
 6727                            Markdown::new(
 6728                                details
 6729                                    .as_ref()
 6730                                    .map(|message| message.message.clone())
 6731                                    .unwrap_or_default(),
 6732                                None,
 6733                                None,
 6734                                cx,
 6735                            )
 6736                        });
 6737                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6738                            position,
 6739                            hide_task: None,
 6740                            popover_bounds: None,
 6741                            popover_state: InlineBlamePopoverState {
 6742                                scroll_handle: ScrollHandle::new(),
 6743                                commit_message: details,
 6744                                markdown,
 6745                            },
 6746                            keyboard_grace: ignore_timeout,
 6747                        });
 6748                        cx.notify();
 6749                    })
 6750                    .ok();
 6751            });
 6752            self.inline_blame_popover_show_task = Some(show_task);
 6753        }
 6754    }
 6755
 6756    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6757        self.inline_blame_popover_show_task.take();
 6758        if let Some(state) = &mut self.inline_blame_popover {
 6759            let hide_task = cx.spawn(async move |editor, cx| {
 6760                cx.background_executor()
 6761                    .timer(std::time::Duration::from_millis(100))
 6762                    .await;
 6763                editor
 6764                    .update(cx, |editor, cx| {
 6765                        editor.inline_blame_popover.take();
 6766                        cx.notify();
 6767                    })
 6768                    .ok();
 6769            });
 6770            state.hide_task = Some(hide_task);
 6771        }
 6772    }
 6773
 6774    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6775        if self.pending_rename.is_some() {
 6776            return None;
 6777        }
 6778
 6779        let provider = self.semantics_provider.clone()?;
 6780        let buffer = self.buffer.read(cx);
 6781        let newest_selection = self.selections.newest_anchor().clone();
 6782        let cursor_position = newest_selection.head();
 6783        let (cursor_buffer, cursor_buffer_position) =
 6784            buffer.text_anchor_for_position(cursor_position, cx)?;
 6785        let (tail_buffer, tail_buffer_position) =
 6786            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6787        if cursor_buffer != tail_buffer {
 6788            return None;
 6789        }
 6790
 6791        let snapshot = cursor_buffer.read(cx).snapshot();
 6792        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6793        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6794        if start_word_range != end_word_range {
 6795            self.document_highlights_task.take();
 6796            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6797            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6798            return None;
 6799        }
 6800
 6801        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6802        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6803            cx.background_executor()
 6804                .timer(Duration::from_millis(debounce))
 6805                .await;
 6806
 6807            let highlights = if let Some(highlights) = cx
 6808                .update(|cx| {
 6809                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6810                })
 6811                .ok()
 6812                .flatten()
 6813            {
 6814                highlights.await.log_err()
 6815            } else {
 6816                None
 6817            };
 6818
 6819            if let Some(highlights) = highlights {
 6820                this.update(cx, |this, cx| {
 6821                    if this.pending_rename.is_some() {
 6822                        return;
 6823                    }
 6824
 6825                    let buffer = this.buffer.read(cx);
 6826                    if buffer
 6827                        .text_anchor_for_position(cursor_position, cx)
 6828                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6829                    {
 6830                        return;
 6831                    }
 6832
 6833                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6834                    let mut write_ranges = Vec::new();
 6835                    let mut read_ranges = Vec::new();
 6836                    for highlight in highlights {
 6837                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6838                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6839                        {
 6840                            let start = highlight
 6841                                .range
 6842                                .start
 6843                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6844                            let end = highlight
 6845                                .range
 6846                                .end
 6847                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6848                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6849                                continue;
 6850                            }
 6851
 6852                            let range = Anchor {
 6853                                buffer_id: Some(buffer_id),
 6854                                excerpt_id,
 6855                                text_anchor: start,
 6856                                diff_base_anchor: None,
 6857                            }..Anchor {
 6858                                buffer_id: Some(buffer_id),
 6859                                excerpt_id,
 6860                                text_anchor: end,
 6861                                diff_base_anchor: None,
 6862                            };
 6863                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6864                                write_ranges.push(range);
 6865                            } else {
 6866                                read_ranges.push(range);
 6867                            }
 6868                        }
 6869                    }
 6870
 6871                    this.highlight_background::<DocumentHighlightRead>(
 6872                        &read_ranges,
 6873                        |theme| theme.colors().editor_document_highlight_read_background,
 6874                        cx,
 6875                    );
 6876                    this.highlight_background::<DocumentHighlightWrite>(
 6877                        &write_ranges,
 6878                        |theme| theme.colors().editor_document_highlight_write_background,
 6879                        cx,
 6880                    );
 6881                    cx.notify();
 6882                })
 6883                .log_err();
 6884            }
 6885        }));
 6886        None
 6887    }
 6888
 6889    fn prepare_highlight_query_from_selection(
 6890        &mut self,
 6891        cx: &mut Context<Editor>,
 6892    ) -> Option<(String, Range<Anchor>)> {
 6893        if matches!(self.mode, EditorMode::SingleLine) {
 6894            return None;
 6895        }
 6896        if !EditorSettings::get_global(cx).selection_highlight {
 6897            return None;
 6898        }
 6899        if self.selections.count() != 1 || self.selections.line_mode {
 6900            return None;
 6901        }
 6902        let selection = self.selections.newest::<Point>(cx);
 6903        if selection.is_empty() || selection.start.row != selection.end.row {
 6904            return None;
 6905        }
 6906        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6907        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6908        let query = multi_buffer_snapshot
 6909            .text_for_range(selection_anchor_range.clone())
 6910            .collect::<String>();
 6911        if query.trim().is_empty() {
 6912            return None;
 6913        }
 6914        Some((query, selection_anchor_range))
 6915    }
 6916
 6917    fn update_selection_occurrence_highlights(
 6918        &mut self,
 6919        query_text: String,
 6920        query_range: Range<Anchor>,
 6921        multi_buffer_range_to_query: Range<Point>,
 6922        use_debounce: bool,
 6923        window: &mut Window,
 6924        cx: &mut Context<Editor>,
 6925    ) -> Task<()> {
 6926        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6927        cx.spawn_in(window, async move |editor, cx| {
 6928            if use_debounce {
 6929                cx.background_executor()
 6930                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6931                    .await;
 6932            }
 6933            let match_task = cx.background_spawn(async move {
 6934                let buffer_ranges = multi_buffer_snapshot
 6935                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6936                    .into_iter()
 6937                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6938                let mut match_ranges = Vec::new();
 6939                let Ok(regex) = project::search::SearchQuery::text(
 6940                    query_text.clone(),
 6941                    false,
 6942                    false,
 6943                    false,
 6944                    Default::default(),
 6945                    Default::default(),
 6946                    false,
 6947                    None,
 6948                ) else {
 6949                    return Vec::default();
 6950                };
 6951                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6952                    match_ranges.extend(
 6953                        regex
 6954                            .search(buffer_snapshot, Some(search_range.clone()))
 6955                            .await
 6956                            .into_iter()
 6957                            .filter_map(|match_range| {
 6958                                let match_start = buffer_snapshot
 6959                                    .anchor_after(search_range.start + match_range.start);
 6960                                let match_end = buffer_snapshot
 6961                                    .anchor_before(search_range.start + match_range.end);
 6962                                let match_anchor_range = Anchor::range_in_buffer(
 6963                                    excerpt_id,
 6964                                    buffer_snapshot.remote_id(),
 6965                                    match_start..match_end,
 6966                                );
 6967                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6968                            }),
 6969                    );
 6970                }
 6971                match_ranges
 6972            });
 6973            let match_ranges = match_task.await;
 6974            editor
 6975                .update_in(cx, |editor, _, cx| {
 6976                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6977                    if !match_ranges.is_empty() {
 6978                        editor.highlight_background::<SelectedTextHighlight>(
 6979                            &match_ranges,
 6980                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6981                            cx,
 6982                        )
 6983                    }
 6984                })
 6985                .log_err();
 6986        })
 6987    }
 6988
 6989    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6990        struct NewlineFold;
 6991        let type_id = std::any::TypeId::of::<NewlineFold>();
 6992        if !self.mode.is_single_line() {
 6993            return;
 6994        }
 6995        let snapshot = self.snapshot(window, cx);
 6996        if snapshot.buffer_snapshot.max_point().row == 0 {
 6997            return;
 6998        }
 6999        let task = cx.background_spawn(async move {
 7000            let new_newlines = snapshot
 7001                .buffer_chars_at(0)
 7002                .filter_map(|(c, i)| {
 7003                    if c == '\n' {
 7004                        Some(
 7005                            snapshot.buffer_snapshot.anchor_after(i)
 7006                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7007                        )
 7008                    } else {
 7009                        None
 7010                    }
 7011                })
 7012                .collect::<Vec<_>>();
 7013            let existing_newlines = snapshot
 7014                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7015                .filter_map(|fold| {
 7016                    if fold.placeholder.type_tag == Some(type_id) {
 7017                        Some(fold.range.start..fold.range.end)
 7018                    } else {
 7019                        None
 7020                    }
 7021                })
 7022                .collect::<Vec<_>>();
 7023
 7024            (new_newlines, existing_newlines)
 7025        });
 7026        self.folding_newlines = cx.spawn(async move |this, cx| {
 7027            let (new_newlines, existing_newlines) = task.await;
 7028            if new_newlines == existing_newlines {
 7029                return;
 7030            }
 7031            let placeholder = FoldPlaceholder {
 7032                render: Arc::new(move |_, _, cx| {
 7033                    div()
 7034                        .bg(cx.theme().status().hint_background)
 7035                        .border_b_1()
 7036                        .size_full()
 7037                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7038                        .border_color(cx.theme().status().hint)
 7039                        .child("\\n")
 7040                        .into_any()
 7041                }),
 7042                constrain_width: false,
 7043                merge_adjacent: false,
 7044                type_tag: Some(type_id),
 7045            };
 7046            let creases = new_newlines
 7047                .into_iter()
 7048                .map(|range| Crease::simple(range, placeholder.clone()))
 7049                .collect();
 7050            this.update(cx, |this, cx| {
 7051                this.display_map.update(cx, |display_map, cx| {
 7052                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7053                    display_map.fold(creases, cx);
 7054                });
 7055            })
 7056            .ok();
 7057        });
 7058    }
 7059
 7060    fn refresh_selected_text_highlights(
 7061        &mut self,
 7062        on_buffer_edit: bool,
 7063        window: &mut Window,
 7064        cx: &mut Context<Editor>,
 7065    ) {
 7066        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7067        else {
 7068            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7069            self.quick_selection_highlight_task.take();
 7070            self.debounced_selection_highlight_task.take();
 7071            return;
 7072        };
 7073        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7074        if on_buffer_edit
 7075            || self
 7076                .quick_selection_highlight_task
 7077                .as_ref()
 7078                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7079        {
 7080            let multi_buffer_visible_start = self
 7081                .scroll_manager
 7082                .anchor()
 7083                .anchor
 7084                .to_point(&multi_buffer_snapshot);
 7085            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7086                multi_buffer_visible_start
 7087                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7088                Bias::Left,
 7089            );
 7090            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7091            self.quick_selection_highlight_task = Some((
 7092                query_range.clone(),
 7093                self.update_selection_occurrence_highlights(
 7094                    query_text.clone(),
 7095                    query_range.clone(),
 7096                    multi_buffer_visible_range,
 7097                    false,
 7098                    window,
 7099                    cx,
 7100                ),
 7101            ));
 7102        }
 7103        if on_buffer_edit
 7104            || self
 7105                .debounced_selection_highlight_task
 7106                .as_ref()
 7107                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7108        {
 7109            let multi_buffer_start = multi_buffer_snapshot
 7110                .anchor_before(0)
 7111                .to_point(&multi_buffer_snapshot);
 7112            let multi_buffer_end = multi_buffer_snapshot
 7113                .anchor_after(multi_buffer_snapshot.len())
 7114                .to_point(&multi_buffer_snapshot);
 7115            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7116            self.debounced_selection_highlight_task = Some((
 7117                query_range.clone(),
 7118                self.update_selection_occurrence_highlights(
 7119                    query_text,
 7120                    query_range,
 7121                    multi_buffer_full_range,
 7122                    true,
 7123                    window,
 7124                    cx,
 7125                ),
 7126            ));
 7127        }
 7128    }
 7129
 7130    pub fn refresh_edit_prediction(
 7131        &mut self,
 7132        debounce: bool,
 7133        user_requested: bool,
 7134        window: &mut Window,
 7135        cx: &mut Context<Self>,
 7136    ) -> Option<()> {
 7137        if DisableAiSettings::get_global(cx).disable_ai {
 7138            return None;
 7139        }
 7140
 7141        let provider = self.edit_prediction_provider()?;
 7142        let cursor = self.selections.newest_anchor().head();
 7143        let (buffer, cursor_buffer_position) =
 7144            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7145
 7146        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7147            self.discard_edit_prediction(false, cx);
 7148            return None;
 7149        }
 7150
 7151        if !user_requested
 7152            && (!self.should_show_edit_predictions()
 7153                || !self.is_focused(window)
 7154                || buffer.read(cx).is_empty())
 7155        {
 7156            self.discard_edit_prediction(false, cx);
 7157            return None;
 7158        }
 7159
 7160        self.update_visible_edit_prediction(window, cx);
 7161        provider.refresh(
 7162            self.project.clone(),
 7163            buffer,
 7164            cursor_buffer_position,
 7165            debounce,
 7166            cx,
 7167        );
 7168        Some(())
 7169    }
 7170
 7171    fn show_edit_predictions_in_menu(&self) -> bool {
 7172        match self.edit_prediction_settings {
 7173            EditPredictionSettings::Disabled => false,
 7174            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7175        }
 7176    }
 7177
 7178    pub fn edit_predictions_enabled(&self) -> bool {
 7179        match self.edit_prediction_settings {
 7180            EditPredictionSettings::Disabled => false,
 7181            EditPredictionSettings::Enabled { .. } => true,
 7182        }
 7183    }
 7184
 7185    fn edit_prediction_requires_modifier(&self) -> bool {
 7186        match self.edit_prediction_settings {
 7187            EditPredictionSettings::Disabled => false,
 7188            EditPredictionSettings::Enabled {
 7189                preview_requires_modifier,
 7190                ..
 7191            } => preview_requires_modifier,
 7192        }
 7193    }
 7194
 7195    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7196        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7197            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7198            self.discard_edit_prediction(false, cx);
 7199        } else {
 7200            let selection = self.selections.newest_anchor();
 7201            let cursor = selection.head();
 7202
 7203            if let Some((buffer, cursor_buffer_position)) =
 7204                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7205            {
 7206                self.edit_prediction_settings =
 7207                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7208            }
 7209        }
 7210    }
 7211
 7212    fn edit_prediction_settings_at_position(
 7213        &self,
 7214        buffer: &Entity<Buffer>,
 7215        buffer_position: language::Anchor,
 7216        cx: &App,
 7217    ) -> EditPredictionSettings {
 7218        if !self.mode.is_full()
 7219            || !self.show_edit_predictions_override.unwrap_or(true)
 7220            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7221        {
 7222            return EditPredictionSettings::Disabled;
 7223        }
 7224
 7225        let buffer = buffer.read(cx);
 7226
 7227        let file = buffer.file();
 7228
 7229        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7230            return EditPredictionSettings::Disabled;
 7231        };
 7232
 7233        let by_provider = matches!(
 7234            self.menu_edit_predictions_policy,
 7235            MenuEditPredictionsPolicy::ByProvider
 7236        );
 7237
 7238        let show_in_menu = by_provider
 7239            && self
 7240                .edit_prediction_provider
 7241                .as_ref()
 7242                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7243
 7244        let preview_requires_modifier =
 7245            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7246
 7247        EditPredictionSettings::Enabled {
 7248            show_in_menu,
 7249            preview_requires_modifier,
 7250        }
 7251    }
 7252
 7253    fn should_show_edit_predictions(&self) -> bool {
 7254        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7255    }
 7256
 7257    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7258        matches!(
 7259            self.edit_prediction_preview,
 7260            EditPredictionPreview::Active { .. }
 7261        )
 7262    }
 7263
 7264    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7265        let cursor = self.selections.newest_anchor().head();
 7266        if let Some((buffer, cursor_position)) =
 7267            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7268        {
 7269            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7270        } else {
 7271            false
 7272        }
 7273    }
 7274
 7275    pub fn supports_minimap(&self, cx: &App) -> bool {
 7276        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7277    }
 7278
 7279    fn edit_predictions_enabled_in_buffer(
 7280        &self,
 7281        buffer: &Entity<Buffer>,
 7282        buffer_position: language::Anchor,
 7283        cx: &App,
 7284    ) -> bool {
 7285        maybe!({
 7286            if self.read_only(cx) {
 7287                return Some(false);
 7288            }
 7289            let provider = self.edit_prediction_provider()?;
 7290            if !provider.is_enabled(buffer, buffer_position, cx) {
 7291                return Some(false);
 7292            }
 7293            let buffer = buffer.read(cx);
 7294            let Some(file) = buffer.file() else {
 7295                return Some(true);
 7296            };
 7297            let settings = all_language_settings(Some(file), cx);
 7298            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7299        })
 7300        .unwrap_or(false)
 7301    }
 7302
 7303    fn cycle_edit_prediction(
 7304        &mut self,
 7305        direction: Direction,
 7306        window: &mut Window,
 7307        cx: &mut Context<Self>,
 7308    ) -> Option<()> {
 7309        let provider = self.edit_prediction_provider()?;
 7310        let cursor = self.selections.newest_anchor().head();
 7311        let (buffer, cursor_buffer_position) =
 7312            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7313        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7314            return None;
 7315        }
 7316
 7317        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7318        self.update_visible_edit_prediction(window, cx);
 7319
 7320        Some(())
 7321    }
 7322
 7323    pub fn show_edit_prediction(
 7324        &mut self,
 7325        _: &ShowEditPrediction,
 7326        window: &mut Window,
 7327        cx: &mut Context<Self>,
 7328    ) {
 7329        if !self.has_active_edit_prediction() {
 7330            self.refresh_edit_prediction(false, true, window, cx);
 7331            return;
 7332        }
 7333
 7334        self.update_visible_edit_prediction(window, cx);
 7335    }
 7336
 7337    pub fn display_cursor_names(
 7338        &mut self,
 7339        _: &DisplayCursorNames,
 7340        window: &mut Window,
 7341        cx: &mut Context<Self>,
 7342    ) {
 7343        self.show_cursor_names(window, cx);
 7344    }
 7345
 7346    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7347        self.show_cursor_names = true;
 7348        cx.notify();
 7349        cx.spawn_in(window, async move |this, cx| {
 7350            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7351            this.update(cx, |this, cx| {
 7352                this.show_cursor_names = false;
 7353                cx.notify()
 7354            })
 7355            .ok()
 7356        })
 7357        .detach();
 7358    }
 7359
 7360    pub fn next_edit_prediction(
 7361        &mut self,
 7362        _: &NextEditPrediction,
 7363        window: &mut Window,
 7364        cx: &mut Context<Self>,
 7365    ) {
 7366        if self.has_active_edit_prediction() {
 7367            self.cycle_edit_prediction(Direction::Next, window, cx);
 7368        } else {
 7369            let is_copilot_disabled = self
 7370                .refresh_edit_prediction(false, true, window, cx)
 7371                .is_none();
 7372            if is_copilot_disabled {
 7373                cx.propagate();
 7374            }
 7375        }
 7376    }
 7377
 7378    pub fn previous_edit_prediction(
 7379        &mut self,
 7380        _: &PreviousEditPrediction,
 7381        window: &mut Window,
 7382        cx: &mut Context<Self>,
 7383    ) {
 7384        if self.has_active_edit_prediction() {
 7385            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7386        } else {
 7387            let is_copilot_disabled = self
 7388                .refresh_edit_prediction(false, true, window, cx)
 7389                .is_none();
 7390            if is_copilot_disabled {
 7391                cx.propagate();
 7392            }
 7393        }
 7394    }
 7395
 7396    pub fn accept_edit_prediction(
 7397        &mut self,
 7398        _: &AcceptEditPrediction,
 7399        window: &mut Window,
 7400        cx: &mut Context<Self>,
 7401    ) {
 7402        if self.show_edit_predictions_in_menu() {
 7403            self.hide_context_menu(window, cx);
 7404        }
 7405
 7406        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7407            return;
 7408        };
 7409
 7410        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7411
 7412        match &active_edit_prediction.completion {
 7413            EditPrediction::Move { target, .. } => {
 7414                let target = *target;
 7415
 7416                if let Some(position_map) = &self.last_position_map {
 7417                    if position_map
 7418                        .visible_row_range
 7419                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7420                        || !self.edit_prediction_requires_modifier()
 7421                    {
 7422                        self.unfold_ranges(&[target..target], true, false, cx);
 7423                        // Note that this is also done in vim's handler of the Tab action.
 7424                        self.change_selections(
 7425                            SelectionEffects::scroll(Autoscroll::newest()),
 7426                            window,
 7427                            cx,
 7428                            |selections| {
 7429                                selections.select_anchor_ranges([target..target]);
 7430                            },
 7431                        );
 7432                        self.clear_row_highlights::<EditPredictionPreview>();
 7433
 7434                        self.edit_prediction_preview
 7435                            .set_previous_scroll_position(None);
 7436                    } else {
 7437                        self.edit_prediction_preview
 7438                            .set_previous_scroll_position(Some(
 7439                                position_map.snapshot.scroll_anchor,
 7440                            ));
 7441
 7442                        self.highlight_rows::<EditPredictionPreview>(
 7443                            target..target,
 7444                            cx.theme().colors().editor_highlighted_line_background,
 7445                            RowHighlightOptions {
 7446                                autoscroll: true,
 7447                                ..Default::default()
 7448                            },
 7449                            cx,
 7450                        );
 7451                        self.request_autoscroll(Autoscroll::fit(), cx);
 7452                    }
 7453                }
 7454            }
 7455            EditPrediction::Edit { edits, .. } => {
 7456                if let Some(provider) = self.edit_prediction_provider() {
 7457                    provider.accept(cx);
 7458                }
 7459
 7460                // Store the transaction ID and selections before applying the edit
 7461                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7462
 7463                let snapshot = self.buffer.read(cx).snapshot(cx);
 7464                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7465
 7466                self.buffer.update(cx, |buffer, cx| {
 7467                    buffer.edit(edits.iter().cloned(), None, cx)
 7468                });
 7469
 7470                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7471                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7472                });
 7473
 7474                let selections = self.selections.disjoint_anchors_arc();
 7475                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7476                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7477                    if has_new_transaction {
 7478                        self.selection_history
 7479                            .insert_transaction(transaction_id_now, selections);
 7480                    }
 7481                }
 7482
 7483                self.update_visible_edit_prediction(window, cx);
 7484                if self.active_edit_prediction.is_none() {
 7485                    self.refresh_edit_prediction(true, true, window, cx);
 7486                }
 7487
 7488                cx.notify();
 7489            }
 7490        }
 7491
 7492        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7493    }
 7494
 7495    pub fn accept_partial_edit_prediction(
 7496        &mut self,
 7497        _: &AcceptPartialEditPrediction,
 7498        window: &mut Window,
 7499        cx: &mut Context<Self>,
 7500    ) {
 7501        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7502            return;
 7503        };
 7504        if self.selections.count() != 1 {
 7505            return;
 7506        }
 7507
 7508        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7509
 7510        match &active_edit_prediction.completion {
 7511            EditPrediction::Move { target, .. } => {
 7512                let target = *target;
 7513                self.change_selections(
 7514                    SelectionEffects::scroll(Autoscroll::newest()),
 7515                    window,
 7516                    cx,
 7517                    |selections| {
 7518                        selections.select_anchor_ranges([target..target]);
 7519                    },
 7520                );
 7521            }
 7522            EditPrediction::Edit { edits, .. } => {
 7523                // Find an insertion that starts at the cursor position.
 7524                let snapshot = self.buffer.read(cx).snapshot(cx);
 7525                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7526                let insertion = edits.iter().find_map(|(range, text)| {
 7527                    let range = range.to_offset(&snapshot);
 7528                    if range.is_empty() && range.start == cursor_offset {
 7529                        Some(text)
 7530                    } else {
 7531                        None
 7532                    }
 7533                });
 7534
 7535                if let Some(text) = insertion {
 7536                    let mut partial_completion = text
 7537                        .chars()
 7538                        .by_ref()
 7539                        .take_while(|c| c.is_alphabetic())
 7540                        .collect::<String>();
 7541                    if partial_completion.is_empty() {
 7542                        partial_completion = text
 7543                            .chars()
 7544                            .by_ref()
 7545                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7546                            .collect::<String>();
 7547                    }
 7548
 7549                    cx.emit(EditorEvent::InputHandled {
 7550                        utf16_range_to_replace: None,
 7551                        text: partial_completion.clone().into(),
 7552                    });
 7553
 7554                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7555
 7556                    self.refresh_edit_prediction(true, true, window, cx);
 7557                    cx.notify();
 7558                } else {
 7559                    self.accept_edit_prediction(&Default::default(), window, cx);
 7560                }
 7561            }
 7562        }
 7563    }
 7564
 7565    fn discard_edit_prediction(
 7566        &mut self,
 7567        should_report_edit_prediction_event: bool,
 7568        cx: &mut Context<Self>,
 7569    ) -> bool {
 7570        if should_report_edit_prediction_event {
 7571            let completion_id = self
 7572                .active_edit_prediction
 7573                .as_ref()
 7574                .and_then(|active_completion| active_completion.completion_id.clone());
 7575
 7576            self.report_edit_prediction_event(completion_id, false, cx);
 7577        }
 7578
 7579        if let Some(provider) = self.edit_prediction_provider() {
 7580            provider.discard(cx);
 7581        }
 7582
 7583        self.take_active_edit_prediction(cx)
 7584    }
 7585
 7586    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7587        let Some(provider) = self.edit_prediction_provider() else {
 7588            return;
 7589        };
 7590
 7591        let Some((_, buffer, _)) = self
 7592            .buffer
 7593            .read(cx)
 7594            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7595        else {
 7596            return;
 7597        };
 7598
 7599        let extension = buffer
 7600            .read(cx)
 7601            .file()
 7602            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7603
 7604        let event_type = match accepted {
 7605            true => "Edit Prediction Accepted",
 7606            false => "Edit Prediction Discarded",
 7607        };
 7608        telemetry::event!(
 7609            event_type,
 7610            provider = provider.name(),
 7611            prediction_id = id,
 7612            suggestion_accepted = accepted,
 7613            file_extension = extension,
 7614        );
 7615    }
 7616
 7617    pub fn has_active_edit_prediction(&self) -> bool {
 7618        self.active_edit_prediction.is_some()
 7619    }
 7620
 7621    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7622        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7623            return false;
 7624        };
 7625
 7626        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7627        self.clear_highlights::<EditPredictionHighlight>(cx);
 7628        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7629        true
 7630    }
 7631
 7632    /// Returns true when we're displaying the edit prediction popover below the cursor
 7633    /// like we are not previewing and the LSP autocomplete menu is visible
 7634    /// or we are in `when_holding_modifier` mode.
 7635    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7636        if self.edit_prediction_preview_is_active()
 7637            || !self.show_edit_predictions_in_menu()
 7638            || !self.edit_predictions_enabled()
 7639        {
 7640            return false;
 7641        }
 7642
 7643        if self.has_visible_completions_menu() {
 7644            return true;
 7645        }
 7646
 7647        has_completion && self.edit_prediction_requires_modifier()
 7648    }
 7649
 7650    fn handle_modifiers_changed(
 7651        &mut self,
 7652        modifiers: Modifiers,
 7653        position_map: &PositionMap,
 7654        window: &mut Window,
 7655        cx: &mut Context<Self>,
 7656    ) {
 7657        if self.show_edit_predictions_in_menu() {
 7658            self.update_edit_prediction_preview(&modifiers, window, cx);
 7659        }
 7660
 7661        self.update_selection_mode(&modifiers, position_map, window, cx);
 7662
 7663        let mouse_position = window.mouse_position();
 7664        if !position_map.text_hitbox.is_hovered(window) {
 7665            return;
 7666        }
 7667
 7668        self.update_hovered_link(
 7669            position_map.point_for_position(mouse_position),
 7670            &position_map.snapshot,
 7671            modifiers,
 7672            window,
 7673            cx,
 7674        )
 7675    }
 7676
 7677    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7678        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7679        if invert {
 7680            match multi_cursor_setting {
 7681                MultiCursorModifier::Alt => modifiers.alt,
 7682                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7683            }
 7684        } else {
 7685            match multi_cursor_setting {
 7686                MultiCursorModifier::Alt => modifiers.secondary(),
 7687                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7688            }
 7689        }
 7690    }
 7691
 7692    fn columnar_selection_mode(
 7693        modifiers: &Modifiers,
 7694        cx: &mut Context<Self>,
 7695    ) -> Option<ColumnarMode> {
 7696        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7697            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7698                Some(ColumnarMode::FromMouse)
 7699            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7700                Some(ColumnarMode::FromSelection)
 7701            } else {
 7702                None
 7703            }
 7704        } else {
 7705            None
 7706        }
 7707    }
 7708
 7709    fn update_selection_mode(
 7710        &mut self,
 7711        modifiers: &Modifiers,
 7712        position_map: &PositionMap,
 7713        window: &mut Window,
 7714        cx: &mut Context<Self>,
 7715    ) {
 7716        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7717            return;
 7718        };
 7719        if self.selections.pending_anchor().is_none() {
 7720            return;
 7721        }
 7722
 7723        let mouse_position = window.mouse_position();
 7724        let point_for_position = position_map.point_for_position(mouse_position);
 7725        let position = point_for_position.previous_valid;
 7726
 7727        self.select(
 7728            SelectPhase::BeginColumnar {
 7729                position,
 7730                reset: false,
 7731                mode,
 7732                goal_column: point_for_position.exact_unclipped.column(),
 7733            },
 7734            window,
 7735            cx,
 7736        );
 7737    }
 7738
 7739    fn update_edit_prediction_preview(
 7740        &mut self,
 7741        modifiers: &Modifiers,
 7742        window: &mut Window,
 7743        cx: &mut Context<Self>,
 7744    ) {
 7745        let mut modifiers_held = false;
 7746        if let Some(accept_keystroke) = self
 7747            .accept_edit_prediction_keybind(false, window, cx)
 7748            .keystroke()
 7749        {
 7750            modifiers_held = modifiers_held
 7751                || (accept_keystroke.modifiers() == modifiers
 7752                    && accept_keystroke.modifiers().modified());
 7753        };
 7754        if let Some(accept_partial_keystroke) = self
 7755            .accept_edit_prediction_keybind(true, window, cx)
 7756            .keystroke()
 7757        {
 7758            modifiers_held = modifiers_held
 7759                || (accept_partial_keystroke.modifiers() == modifiers
 7760                    && accept_partial_keystroke.modifiers().modified());
 7761        }
 7762
 7763        if modifiers_held {
 7764            if matches!(
 7765                self.edit_prediction_preview,
 7766                EditPredictionPreview::Inactive { .. }
 7767            ) {
 7768                self.edit_prediction_preview = EditPredictionPreview::Active {
 7769                    previous_scroll_position: None,
 7770                    since: Instant::now(),
 7771                };
 7772
 7773                self.update_visible_edit_prediction(window, cx);
 7774                cx.notify();
 7775            }
 7776        } else if let EditPredictionPreview::Active {
 7777            previous_scroll_position,
 7778            since,
 7779        } = self.edit_prediction_preview
 7780        {
 7781            if let (Some(previous_scroll_position), Some(position_map)) =
 7782                (previous_scroll_position, self.last_position_map.as_ref())
 7783            {
 7784                self.set_scroll_position(
 7785                    previous_scroll_position
 7786                        .scroll_position(&position_map.snapshot.display_snapshot),
 7787                    window,
 7788                    cx,
 7789                );
 7790            }
 7791
 7792            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7793                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7794            };
 7795            self.clear_row_highlights::<EditPredictionPreview>();
 7796            self.update_visible_edit_prediction(window, cx);
 7797            cx.notify();
 7798        }
 7799    }
 7800
 7801    fn update_visible_edit_prediction(
 7802        &mut self,
 7803        _window: &mut Window,
 7804        cx: &mut Context<Self>,
 7805    ) -> Option<()> {
 7806        if DisableAiSettings::get_global(cx).disable_ai {
 7807            return None;
 7808        }
 7809
 7810        if self.ime_transaction.is_some() {
 7811            self.discard_edit_prediction(false, cx);
 7812            return None;
 7813        }
 7814
 7815        let selection = self.selections.newest_anchor();
 7816        let cursor = selection.head();
 7817        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7818        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7819        let excerpt_id = cursor.excerpt_id;
 7820
 7821        let show_in_menu = self.show_edit_predictions_in_menu();
 7822        let completions_menu_has_precedence = !show_in_menu
 7823            && (self.context_menu.borrow().is_some()
 7824                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7825
 7826        if completions_menu_has_precedence
 7827            || !offset_selection.is_empty()
 7828            || self
 7829                .active_edit_prediction
 7830                .as_ref()
 7831                .is_some_and(|completion| {
 7832                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7833                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7834                    !invalidation_range.contains(&offset_selection.head())
 7835                })
 7836        {
 7837            self.discard_edit_prediction(false, cx);
 7838            return None;
 7839        }
 7840
 7841        self.take_active_edit_prediction(cx);
 7842        let Some(provider) = self.edit_prediction_provider() else {
 7843            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7844            return None;
 7845        };
 7846
 7847        let (buffer, cursor_buffer_position) =
 7848            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7849
 7850        self.edit_prediction_settings =
 7851            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7852
 7853        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7854            self.discard_edit_prediction(false, cx);
 7855            return None;
 7856        };
 7857
 7858        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7859
 7860        if self.edit_prediction_indent_conflict {
 7861            let cursor_point = cursor.to_point(&multibuffer);
 7862
 7863            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7864
 7865            if let Some((_, indent)) = indents.iter().next()
 7866                && indent.len == cursor_point.column
 7867            {
 7868                self.edit_prediction_indent_conflict = false;
 7869            }
 7870        }
 7871
 7872        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7873        let edits = edit_prediction
 7874            .edits
 7875            .into_iter()
 7876            .flat_map(|(range, new_text)| {
 7877                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7878                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7879                Some((start..end, new_text))
 7880            })
 7881            .collect::<Vec<_>>();
 7882        if edits.is_empty() {
 7883            return None;
 7884        }
 7885
 7886        let first_edit_start = edits.first().unwrap().0.start;
 7887        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7888        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7889
 7890        let last_edit_end = edits.last().unwrap().0.end;
 7891        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7892        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7893
 7894        let cursor_row = cursor.to_point(&multibuffer).row;
 7895
 7896        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7897
 7898        let mut inlay_ids = Vec::new();
 7899        let invalidation_row_range;
 7900        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7901            Some(cursor_row..edit_end_row)
 7902        } else if cursor_row > edit_end_row {
 7903            Some(edit_start_row..cursor_row)
 7904        } else {
 7905            None
 7906        };
 7907        let supports_jump = self
 7908            .edit_prediction_provider
 7909            .as_ref()
 7910            .map(|provider| provider.provider.supports_jump_to_edit())
 7911            .unwrap_or(true);
 7912
 7913        let is_move = supports_jump
 7914            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7915        let completion = if is_move {
 7916            invalidation_row_range =
 7917                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7918            let target = first_edit_start;
 7919            EditPrediction::Move { target, snapshot }
 7920        } else {
 7921            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7922                && !self.edit_predictions_hidden_for_vim_mode;
 7923
 7924            if show_completions_in_buffer {
 7925                if edits
 7926                    .iter()
 7927                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7928                {
 7929                    let mut inlays = Vec::new();
 7930                    for (range, new_text) in &edits {
 7931                        let inlay = Inlay::edit_prediction(
 7932                            post_inc(&mut self.next_inlay_id),
 7933                            range.start,
 7934                            new_text.as_str(),
 7935                        );
 7936                        inlay_ids.push(inlay.id);
 7937                        inlays.push(inlay);
 7938                    }
 7939
 7940                    self.splice_inlays(&[], inlays, cx);
 7941                } else {
 7942                    let background_color = cx.theme().status().deleted_background;
 7943                    self.highlight_text::<EditPredictionHighlight>(
 7944                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7945                        HighlightStyle {
 7946                            background_color: Some(background_color),
 7947                            ..Default::default()
 7948                        },
 7949                        cx,
 7950                    );
 7951                }
 7952            }
 7953
 7954            invalidation_row_range = edit_start_row..edit_end_row;
 7955
 7956            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7957                if provider.show_tab_accept_marker() {
 7958                    EditDisplayMode::TabAccept
 7959                } else {
 7960                    EditDisplayMode::Inline
 7961                }
 7962            } else {
 7963                EditDisplayMode::DiffPopover
 7964            };
 7965
 7966            EditPrediction::Edit {
 7967                edits,
 7968                edit_preview: edit_prediction.edit_preview,
 7969                display_mode,
 7970                snapshot,
 7971            }
 7972        };
 7973
 7974        let invalidation_range = multibuffer
 7975            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7976            ..multibuffer.anchor_after(Point::new(
 7977                invalidation_row_range.end,
 7978                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7979            ));
 7980
 7981        self.stale_edit_prediction_in_menu = None;
 7982        self.active_edit_prediction = Some(EditPredictionState {
 7983            inlay_ids,
 7984            completion,
 7985            completion_id: edit_prediction.id,
 7986            invalidation_range,
 7987        });
 7988
 7989        cx.notify();
 7990
 7991        Some(())
 7992    }
 7993
 7994    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7995        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7996    }
 7997
 7998    fn clear_tasks(&mut self) {
 7999        self.tasks.clear()
 8000    }
 8001
 8002    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8003        if self.tasks.insert(key, value).is_some() {
 8004            // This case should hopefully be rare, but just in case...
 8005            log::error!(
 8006                "multiple different run targets found on a single line, only the last target will be rendered"
 8007            )
 8008        }
 8009    }
 8010
 8011    /// Get all display points of breakpoints that will be rendered within editor
 8012    ///
 8013    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8014    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8015    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8016    fn active_breakpoints(
 8017        &self,
 8018        range: Range<DisplayRow>,
 8019        window: &mut Window,
 8020        cx: &mut Context<Self>,
 8021    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8022        let mut breakpoint_display_points = HashMap::default();
 8023
 8024        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8025            return breakpoint_display_points;
 8026        };
 8027
 8028        let snapshot = self.snapshot(window, cx);
 8029
 8030        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8031        let Some(project) = self.project() else {
 8032            return breakpoint_display_points;
 8033        };
 8034
 8035        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8036            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8037
 8038        for (buffer_snapshot, range, excerpt_id) in
 8039            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8040        {
 8041            let Some(buffer) = project
 8042                .read(cx)
 8043                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8044            else {
 8045                continue;
 8046            };
 8047            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8048                &buffer,
 8049                Some(
 8050                    buffer_snapshot.anchor_before(range.start)
 8051                        ..buffer_snapshot.anchor_after(range.end),
 8052                ),
 8053                buffer_snapshot,
 8054                cx,
 8055            );
 8056            for (breakpoint, state) in breakpoints {
 8057                let multi_buffer_anchor =
 8058                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8059                let position = multi_buffer_anchor
 8060                    .to_point(multi_buffer_snapshot)
 8061                    .to_display_point(&snapshot);
 8062
 8063                breakpoint_display_points.insert(
 8064                    position.row(),
 8065                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8066                );
 8067            }
 8068        }
 8069
 8070        breakpoint_display_points
 8071    }
 8072
 8073    fn breakpoint_context_menu(
 8074        &self,
 8075        anchor: Anchor,
 8076        window: &mut Window,
 8077        cx: &mut Context<Self>,
 8078    ) -> Entity<ui::ContextMenu> {
 8079        let weak_editor = cx.weak_entity();
 8080        let focus_handle = self.focus_handle(cx);
 8081
 8082        let row = self
 8083            .buffer
 8084            .read(cx)
 8085            .snapshot(cx)
 8086            .summary_for_anchor::<Point>(&anchor)
 8087            .row;
 8088
 8089        let breakpoint = self
 8090            .breakpoint_at_row(row, window, cx)
 8091            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8092
 8093        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8094            "Edit Log Breakpoint"
 8095        } else {
 8096            "Set Log Breakpoint"
 8097        };
 8098
 8099        let condition_breakpoint_msg = if breakpoint
 8100            .as_ref()
 8101            .is_some_and(|bp| bp.1.condition.is_some())
 8102        {
 8103            "Edit Condition Breakpoint"
 8104        } else {
 8105            "Set Condition Breakpoint"
 8106        };
 8107
 8108        let hit_condition_breakpoint_msg = if breakpoint
 8109            .as_ref()
 8110            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8111        {
 8112            "Edit Hit Condition Breakpoint"
 8113        } else {
 8114            "Set Hit Condition Breakpoint"
 8115        };
 8116
 8117        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8118            "Unset Breakpoint"
 8119        } else {
 8120            "Set Breakpoint"
 8121        };
 8122
 8123        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8124
 8125        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8126            BreakpointState::Enabled => Some("Disable"),
 8127            BreakpointState::Disabled => Some("Enable"),
 8128        });
 8129
 8130        let (anchor, breakpoint) =
 8131            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8132
 8133        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8134            menu.on_blur_subscription(Subscription::new(|| {}))
 8135                .context(focus_handle)
 8136                .when(run_to_cursor, |this| {
 8137                    let weak_editor = weak_editor.clone();
 8138                    this.entry("Run to cursor", None, move |window, cx| {
 8139                        weak_editor
 8140                            .update(cx, |editor, cx| {
 8141                                editor.change_selections(
 8142                                    SelectionEffects::no_scroll(),
 8143                                    window,
 8144                                    cx,
 8145                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8146                                );
 8147                            })
 8148                            .ok();
 8149
 8150                        window.dispatch_action(Box::new(RunToCursor), cx);
 8151                    })
 8152                    .separator()
 8153                })
 8154                .when_some(toggle_state_msg, |this, msg| {
 8155                    this.entry(msg, None, {
 8156                        let weak_editor = weak_editor.clone();
 8157                        let breakpoint = breakpoint.clone();
 8158                        move |_window, cx| {
 8159                            weak_editor
 8160                                .update(cx, |this, cx| {
 8161                                    this.edit_breakpoint_at_anchor(
 8162                                        anchor,
 8163                                        breakpoint.as_ref().clone(),
 8164                                        BreakpointEditAction::InvertState,
 8165                                        cx,
 8166                                    );
 8167                                })
 8168                                .log_err();
 8169                        }
 8170                    })
 8171                })
 8172                .entry(set_breakpoint_msg, None, {
 8173                    let weak_editor = weak_editor.clone();
 8174                    let breakpoint = breakpoint.clone();
 8175                    move |_window, cx| {
 8176                        weak_editor
 8177                            .update(cx, |this, cx| {
 8178                                this.edit_breakpoint_at_anchor(
 8179                                    anchor,
 8180                                    breakpoint.as_ref().clone(),
 8181                                    BreakpointEditAction::Toggle,
 8182                                    cx,
 8183                                );
 8184                            })
 8185                            .log_err();
 8186                    }
 8187                })
 8188                .entry(log_breakpoint_msg, None, {
 8189                    let breakpoint = breakpoint.clone();
 8190                    let weak_editor = weak_editor.clone();
 8191                    move |window, cx| {
 8192                        weak_editor
 8193                            .update(cx, |this, cx| {
 8194                                this.add_edit_breakpoint_block(
 8195                                    anchor,
 8196                                    breakpoint.as_ref(),
 8197                                    BreakpointPromptEditAction::Log,
 8198                                    window,
 8199                                    cx,
 8200                                );
 8201                            })
 8202                            .log_err();
 8203                    }
 8204                })
 8205                .entry(condition_breakpoint_msg, None, {
 8206                    let breakpoint = breakpoint.clone();
 8207                    let weak_editor = weak_editor.clone();
 8208                    move |window, cx| {
 8209                        weak_editor
 8210                            .update(cx, |this, cx| {
 8211                                this.add_edit_breakpoint_block(
 8212                                    anchor,
 8213                                    breakpoint.as_ref(),
 8214                                    BreakpointPromptEditAction::Condition,
 8215                                    window,
 8216                                    cx,
 8217                                );
 8218                            })
 8219                            .log_err();
 8220                    }
 8221                })
 8222                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8223                    weak_editor
 8224                        .update(cx, |this, cx| {
 8225                            this.add_edit_breakpoint_block(
 8226                                anchor,
 8227                                breakpoint.as_ref(),
 8228                                BreakpointPromptEditAction::HitCondition,
 8229                                window,
 8230                                cx,
 8231                            );
 8232                        })
 8233                        .log_err();
 8234                })
 8235        })
 8236    }
 8237
 8238    fn render_breakpoint(
 8239        &self,
 8240        position: Anchor,
 8241        row: DisplayRow,
 8242        breakpoint: &Breakpoint,
 8243        state: Option<BreakpointSessionState>,
 8244        cx: &mut Context<Self>,
 8245    ) -> IconButton {
 8246        let is_rejected = state.is_some_and(|s| !s.verified);
 8247        // Is it a breakpoint that shows up when hovering over gutter?
 8248        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8249            (false, false),
 8250            |PhantomBreakpointIndicator {
 8251                 is_active,
 8252                 display_row,
 8253                 collides_with_existing_breakpoint,
 8254             }| {
 8255                (
 8256                    is_active && display_row == row,
 8257                    collides_with_existing_breakpoint,
 8258                )
 8259            },
 8260        );
 8261
 8262        let (color, icon) = {
 8263            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8264                (false, false) => ui::IconName::DebugBreakpoint,
 8265                (true, false) => ui::IconName::DebugLogBreakpoint,
 8266                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8267                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8268            };
 8269
 8270            let color = if is_phantom {
 8271                Color::Hint
 8272            } else if is_rejected {
 8273                Color::Disabled
 8274            } else {
 8275                Color::Debugger
 8276            };
 8277
 8278            (color, icon)
 8279        };
 8280
 8281        let breakpoint = Arc::from(breakpoint.clone());
 8282
 8283        let alt_as_text = gpui::Keystroke {
 8284            modifiers: Modifiers::secondary_key(),
 8285            ..Default::default()
 8286        };
 8287        let primary_action_text = if breakpoint.is_disabled() {
 8288            "Enable breakpoint"
 8289        } else if is_phantom && !collides_with_existing {
 8290            "Set breakpoint"
 8291        } else {
 8292            "Unset breakpoint"
 8293        };
 8294        let focus_handle = self.focus_handle.clone();
 8295
 8296        let meta = if is_rejected {
 8297            SharedString::from("No executable code is associated with this line.")
 8298        } else if collides_with_existing && !breakpoint.is_disabled() {
 8299            SharedString::from(format!(
 8300                "{alt_as_text}-click to disable,\nright-click for more options."
 8301            ))
 8302        } else {
 8303            SharedString::from("Right-click for more options.")
 8304        };
 8305        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8306            .icon_size(IconSize::XSmall)
 8307            .size(ui::ButtonSize::None)
 8308            .when(is_rejected, |this| {
 8309                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8310            })
 8311            .icon_color(color)
 8312            .style(ButtonStyle::Transparent)
 8313            .on_click(cx.listener({
 8314                move |editor, event: &ClickEvent, window, cx| {
 8315                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8316                        BreakpointEditAction::InvertState
 8317                    } else {
 8318                        BreakpointEditAction::Toggle
 8319                    };
 8320
 8321                    window.focus(&editor.focus_handle(cx));
 8322                    editor.edit_breakpoint_at_anchor(
 8323                        position,
 8324                        breakpoint.as_ref().clone(),
 8325                        edit_action,
 8326                        cx,
 8327                    );
 8328                }
 8329            }))
 8330            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8331                editor.set_breakpoint_context_menu(
 8332                    row,
 8333                    Some(position),
 8334                    event.position(),
 8335                    window,
 8336                    cx,
 8337                );
 8338            }))
 8339            .tooltip(move |window, cx| {
 8340                Tooltip::with_meta_in(
 8341                    primary_action_text,
 8342                    Some(&ToggleBreakpoint),
 8343                    meta.clone(),
 8344                    &focus_handle,
 8345                    window,
 8346                    cx,
 8347                )
 8348            })
 8349    }
 8350
 8351    fn build_tasks_context(
 8352        project: &Entity<Project>,
 8353        buffer: &Entity<Buffer>,
 8354        buffer_row: u32,
 8355        tasks: &Arc<RunnableTasks>,
 8356        cx: &mut Context<Self>,
 8357    ) -> Task<Option<task::TaskContext>> {
 8358        let position = Point::new(buffer_row, tasks.column);
 8359        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8360        let location = Location {
 8361            buffer: buffer.clone(),
 8362            range: range_start..range_start,
 8363        };
 8364        // Fill in the environmental variables from the tree-sitter captures
 8365        let mut captured_task_variables = TaskVariables::default();
 8366        for (capture_name, value) in tasks.extra_variables.clone() {
 8367            captured_task_variables.insert(
 8368                task::VariableName::Custom(capture_name.into()),
 8369                value.clone(),
 8370            );
 8371        }
 8372        project.update(cx, |project, cx| {
 8373            project.task_store().update(cx, |task_store, cx| {
 8374                task_store.task_context_for_location(captured_task_variables, location, cx)
 8375            })
 8376        })
 8377    }
 8378
 8379    pub fn spawn_nearest_task(
 8380        &mut self,
 8381        action: &SpawnNearestTask,
 8382        window: &mut Window,
 8383        cx: &mut Context<Self>,
 8384    ) {
 8385        let Some((workspace, _)) = self.workspace.clone() else {
 8386            return;
 8387        };
 8388        let Some(project) = self.project.clone() else {
 8389            return;
 8390        };
 8391
 8392        // Try to find a closest, enclosing node using tree-sitter that has a task
 8393        let Some((buffer, buffer_row, tasks)) = self
 8394            .find_enclosing_node_task(cx)
 8395            // Or find the task that's closest in row-distance.
 8396            .or_else(|| self.find_closest_task(cx))
 8397        else {
 8398            return;
 8399        };
 8400
 8401        let reveal_strategy = action.reveal;
 8402        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8403        cx.spawn_in(window, async move |_, cx| {
 8404            let context = task_context.await?;
 8405            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8406
 8407            let resolved = &mut resolved_task.resolved;
 8408            resolved.reveal = reveal_strategy;
 8409
 8410            workspace
 8411                .update_in(cx, |workspace, window, cx| {
 8412                    workspace.schedule_resolved_task(
 8413                        task_source_kind,
 8414                        resolved_task,
 8415                        false,
 8416                        window,
 8417                        cx,
 8418                    );
 8419                })
 8420                .ok()
 8421        })
 8422        .detach();
 8423    }
 8424
 8425    fn find_closest_task(
 8426        &mut self,
 8427        cx: &mut Context<Self>,
 8428    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8429        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8430
 8431        let ((buffer_id, row), tasks) = self
 8432            .tasks
 8433            .iter()
 8434            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8435
 8436        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8437        let tasks = Arc::new(tasks.to_owned());
 8438        Some((buffer, *row, tasks))
 8439    }
 8440
 8441    fn find_enclosing_node_task(
 8442        &mut self,
 8443        cx: &mut Context<Self>,
 8444    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8445        let snapshot = self.buffer.read(cx).snapshot(cx);
 8446        let offset = self.selections.newest::<usize>(cx).head();
 8447        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8448        let buffer_id = excerpt.buffer().remote_id();
 8449
 8450        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8451        let mut cursor = layer.node().walk();
 8452
 8453        while cursor.goto_first_child_for_byte(offset).is_some() {
 8454            if cursor.node().end_byte() == offset {
 8455                cursor.goto_next_sibling();
 8456            }
 8457        }
 8458
 8459        // Ascend to the smallest ancestor that contains the range and has a task.
 8460        loop {
 8461            let node = cursor.node();
 8462            let node_range = node.byte_range();
 8463            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8464
 8465            // Check if this node contains our offset
 8466            if node_range.start <= offset && node_range.end >= offset {
 8467                // If it contains offset, check for task
 8468                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8469                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8470                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8471                }
 8472            }
 8473
 8474            if !cursor.goto_parent() {
 8475                break;
 8476            }
 8477        }
 8478        None
 8479    }
 8480
 8481    fn render_run_indicator(
 8482        &self,
 8483        _style: &EditorStyle,
 8484        is_active: bool,
 8485        row: DisplayRow,
 8486        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8487        cx: &mut Context<Self>,
 8488    ) -> IconButton {
 8489        let color = Color::Muted;
 8490        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8491
 8492        IconButton::new(
 8493            ("run_indicator", row.0 as usize),
 8494            ui::IconName::PlayOutlined,
 8495        )
 8496        .shape(ui::IconButtonShape::Square)
 8497        .icon_size(IconSize::XSmall)
 8498        .icon_color(color)
 8499        .toggle_state(is_active)
 8500        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8501            let quick_launch = match e {
 8502                ClickEvent::Keyboard(_) => true,
 8503                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8504            };
 8505
 8506            window.focus(&editor.focus_handle(cx));
 8507            editor.toggle_code_actions(
 8508                &ToggleCodeActions {
 8509                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8510                    quick_launch,
 8511                },
 8512                window,
 8513                cx,
 8514            );
 8515        }))
 8516        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8517            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8518        }))
 8519    }
 8520
 8521    pub fn context_menu_visible(&self) -> bool {
 8522        !self.edit_prediction_preview_is_active()
 8523            && self
 8524                .context_menu
 8525                .borrow()
 8526                .as_ref()
 8527                .is_some_and(|menu| menu.visible())
 8528    }
 8529
 8530    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8531        self.context_menu
 8532            .borrow()
 8533            .as_ref()
 8534            .map(|menu| menu.origin())
 8535    }
 8536
 8537    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8538        self.context_menu_options = Some(options);
 8539    }
 8540
 8541    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8542    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8543
 8544    fn render_edit_prediction_popover(
 8545        &mut self,
 8546        text_bounds: &Bounds<Pixels>,
 8547        content_origin: gpui::Point<Pixels>,
 8548        right_margin: Pixels,
 8549        editor_snapshot: &EditorSnapshot,
 8550        visible_row_range: Range<DisplayRow>,
 8551        scroll_top: f32,
 8552        scroll_bottom: f32,
 8553        line_layouts: &[LineWithInvisibles],
 8554        line_height: Pixels,
 8555        scroll_pixel_position: gpui::Point<Pixels>,
 8556        newest_selection_head: Option<DisplayPoint>,
 8557        editor_width: Pixels,
 8558        style: &EditorStyle,
 8559        window: &mut Window,
 8560        cx: &mut App,
 8561    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8562        if self.mode().is_minimap() {
 8563            return None;
 8564        }
 8565        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8566
 8567        if self.edit_prediction_visible_in_cursor_popover(true) {
 8568            return None;
 8569        }
 8570
 8571        match &active_edit_prediction.completion {
 8572            EditPrediction::Move { target, .. } => {
 8573                let target_display_point = target.to_display_point(editor_snapshot);
 8574
 8575                if self.edit_prediction_requires_modifier() {
 8576                    if !self.edit_prediction_preview_is_active() {
 8577                        return None;
 8578                    }
 8579
 8580                    self.render_edit_prediction_modifier_jump_popover(
 8581                        text_bounds,
 8582                        content_origin,
 8583                        visible_row_range,
 8584                        line_layouts,
 8585                        line_height,
 8586                        scroll_pixel_position,
 8587                        newest_selection_head,
 8588                        target_display_point,
 8589                        window,
 8590                        cx,
 8591                    )
 8592                } else {
 8593                    self.render_edit_prediction_eager_jump_popover(
 8594                        text_bounds,
 8595                        content_origin,
 8596                        editor_snapshot,
 8597                        visible_row_range,
 8598                        scroll_top,
 8599                        scroll_bottom,
 8600                        line_height,
 8601                        scroll_pixel_position,
 8602                        target_display_point,
 8603                        editor_width,
 8604                        window,
 8605                        cx,
 8606                    )
 8607                }
 8608            }
 8609            EditPrediction::Edit {
 8610                display_mode: EditDisplayMode::Inline,
 8611                ..
 8612            } => None,
 8613            EditPrediction::Edit {
 8614                display_mode: EditDisplayMode::TabAccept,
 8615                edits,
 8616                ..
 8617            } => {
 8618                let range = &edits.first()?.0;
 8619                let target_display_point = range.end.to_display_point(editor_snapshot);
 8620
 8621                self.render_edit_prediction_end_of_line_popover(
 8622                    "Accept",
 8623                    editor_snapshot,
 8624                    visible_row_range,
 8625                    target_display_point,
 8626                    line_height,
 8627                    scroll_pixel_position,
 8628                    content_origin,
 8629                    editor_width,
 8630                    window,
 8631                    cx,
 8632                )
 8633            }
 8634            EditPrediction::Edit {
 8635                edits,
 8636                edit_preview,
 8637                display_mode: EditDisplayMode::DiffPopover,
 8638                snapshot,
 8639            } => self.render_edit_prediction_diff_popover(
 8640                text_bounds,
 8641                content_origin,
 8642                right_margin,
 8643                editor_snapshot,
 8644                visible_row_range,
 8645                line_layouts,
 8646                line_height,
 8647                scroll_pixel_position,
 8648                newest_selection_head,
 8649                editor_width,
 8650                style,
 8651                edits,
 8652                edit_preview,
 8653                snapshot,
 8654                window,
 8655                cx,
 8656            ),
 8657        }
 8658    }
 8659
 8660    fn render_edit_prediction_modifier_jump_popover(
 8661        &mut self,
 8662        text_bounds: &Bounds<Pixels>,
 8663        content_origin: gpui::Point<Pixels>,
 8664        visible_row_range: Range<DisplayRow>,
 8665        line_layouts: &[LineWithInvisibles],
 8666        line_height: Pixels,
 8667        scroll_pixel_position: gpui::Point<Pixels>,
 8668        newest_selection_head: Option<DisplayPoint>,
 8669        target_display_point: DisplayPoint,
 8670        window: &mut Window,
 8671        cx: &mut App,
 8672    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8673        let scrolled_content_origin =
 8674            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8675
 8676        const SCROLL_PADDING_Y: Pixels = px(12.);
 8677
 8678        if target_display_point.row() < visible_row_range.start {
 8679            return self.render_edit_prediction_scroll_popover(
 8680                |_| SCROLL_PADDING_Y,
 8681                IconName::ArrowUp,
 8682                visible_row_range,
 8683                line_layouts,
 8684                newest_selection_head,
 8685                scrolled_content_origin,
 8686                window,
 8687                cx,
 8688            );
 8689        } else if target_display_point.row() >= visible_row_range.end {
 8690            return self.render_edit_prediction_scroll_popover(
 8691                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8692                IconName::ArrowDown,
 8693                visible_row_range,
 8694                line_layouts,
 8695                newest_selection_head,
 8696                scrolled_content_origin,
 8697                window,
 8698                cx,
 8699            );
 8700        }
 8701
 8702        const POLE_WIDTH: Pixels = px(2.);
 8703
 8704        let line_layout =
 8705            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8706        let target_column = target_display_point.column() as usize;
 8707
 8708        let target_x = line_layout.x_for_index(target_column);
 8709        let target_y =
 8710            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8711
 8712        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8713
 8714        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8715        border_color.l += 0.001;
 8716
 8717        let mut element = v_flex()
 8718            .items_end()
 8719            .when(flag_on_right, |el| el.items_start())
 8720            .child(if flag_on_right {
 8721                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8722                    .rounded_bl(px(0.))
 8723                    .rounded_tl(px(0.))
 8724                    .border_l_2()
 8725                    .border_color(border_color)
 8726            } else {
 8727                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8728                    .rounded_br(px(0.))
 8729                    .rounded_tr(px(0.))
 8730                    .border_r_2()
 8731                    .border_color(border_color)
 8732            })
 8733            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8734            .into_any();
 8735
 8736        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8737
 8738        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8739            - point(
 8740                if flag_on_right {
 8741                    POLE_WIDTH
 8742                } else {
 8743                    size.width - POLE_WIDTH
 8744                },
 8745                size.height - line_height,
 8746            );
 8747
 8748        origin.x = origin.x.max(content_origin.x);
 8749
 8750        element.prepaint_at(origin, window, cx);
 8751
 8752        Some((element, origin))
 8753    }
 8754
 8755    fn render_edit_prediction_scroll_popover(
 8756        &mut self,
 8757        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8758        scroll_icon: IconName,
 8759        visible_row_range: Range<DisplayRow>,
 8760        line_layouts: &[LineWithInvisibles],
 8761        newest_selection_head: Option<DisplayPoint>,
 8762        scrolled_content_origin: gpui::Point<Pixels>,
 8763        window: &mut Window,
 8764        cx: &mut App,
 8765    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8766        let mut element = self
 8767            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8768            .into_any();
 8769
 8770        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8771
 8772        let cursor = newest_selection_head?;
 8773        let cursor_row_layout =
 8774            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8775        let cursor_column = cursor.column() as usize;
 8776
 8777        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8778
 8779        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8780
 8781        element.prepaint_at(origin, window, cx);
 8782        Some((element, origin))
 8783    }
 8784
 8785    fn render_edit_prediction_eager_jump_popover(
 8786        &mut self,
 8787        text_bounds: &Bounds<Pixels>,
 8788        content_origin: gpui::Point<Pixels>,
 8789        editor_snapshot: &EditorSnapshot,
 8790        visible_row_range: Range<DisplayRow>,
 8791        scroll_top: f32,
 8792        scroll_bottom: f32,
 8793        line_height: Pixels,
 8794        scroll_pixel_position: gpui::Point<Pixels>,
 8795        target_display_point: DisplayPoint,
 8796        editor_width: Pixels,
 8797        window: &mut Window,
 8798        cx: &mut App,
 8799    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8800        if target_display_point.row().as_f32() < scroll_top {
 8801            let mut element = self
 8802                .render_edit_prediction_line_popover(
 8803                    "Jump to Edit",
 8804                    Some(IconName::ArrowUp),
 8805                    window,
 8806                    cx,
 8807                )?
 8808                .into_any();
 8809
 8810            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8811            let offset = point(
 8812                (text_bounds.size.width - size.width) / 2.,
 8813                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8814            );
 8815
 8816            let origin = text_bounds.origin + offset;
 8817            element.prepaint_at(origin, window, cx);
 8818            Some((element, origin))
 8819        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8820            let mut element = self
 8821                .render_edit_prediction_line_popover(
 8822                    "Jump to Edit",
 8823                    Some(IconName::ArrowDown),
 8824                    window,
 8825                    cx,
 8826                )?
 8827                .into_any();
 8828
 8829            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8830            let offset = point(
 8831                (text_bounds.size.width - size.width) / 2.,
 8832                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8833            );
 8834
 8835            let origin = text_bounds.origin + offset;
 8836            element.prepaint_at(origin, window, cx);
 8837            Some((element, origin))
 8838        } else {
 8839            self.render_edit_prediction_end_of_line_popover(
 8840                "Jump to Edit",
 8841                editor_snapshot,
 8842                visible_row_range,
 8843                target_display_point,
 8844                line_height,
 8845                scroll_pixel_position,
 8846                content_origin,
 8847                editor_width,
 8848                window,
 8849                cx,
 8850            )
 8851        }
 8852    }
 8853
 8854    fn render_edit_prediction_end_of_line_popover(
 8855        self: &mut Editor,
 8856        label: &'static str,
 8857        editor_snapshot: &EditorSnapshot,
 8858        visible_row_range: Range<DisplayRow>,
 8859        target_display_point: DisplayPoint,
 8860        line_height: Pixels,
 8861        scroll_pixel_position: gpui::Point<Pixels>,
 8862        content_origin: gpui::Point<Pixels>,
 8863        editor_width: Pixels,
 8864        window: &mut Window,
 8865        cx: &mut App,
 8866    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8867        let target_line_end = DisplayPoint::new(
 8868            target_display_point.row(),
 8869            editor_snapshot.line_len(target_display_point.row()),
 8870        );
 8871
 8872        let mut element = self
 8873            .render_edit_prediction_line_popover(label, None, window, cx)?
 8874            .into_any();
 8875
 8876        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8877
 8878        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8879
 8880        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8881        let mut origin = start_point
 8882            + line_origin
 8883            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8884        origin.x = origin.x.max(content_origin.x);
 8885
 8886        let max_x = content_origin.x + editor_width - size.width;
 8887
 8888        if origin.x > max_x {
 8889            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8890
 8891            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8892                origin.y += offset;
 8893                IconName::ArrowUp
 8894            } else {
 8895                origin.y -= offset;
 8896                IconName::ArrowDown
 8897            };
 8898
 8899            element = self
 8900                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8901                .into_any();
 8902
 8903            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8904
 8905            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8906        }
 8907
 8908        element.prepaint_at(origin, window, cx);
 8909        Some((element, origin))
 8910    }
 8911
 8912    fn render_edit_prediction_diff_popover(
 8913        self: &Editor,
 8914        text_bounds: &Bounds<Pixels>,
 8915        content_origin: gpui::Point<Pixels>,
 8916        right_margin: Pixels,
 8917        editor_snapshot: &EditorSnapshot,
 8918        visible_row_range: Range<DisplayRow>,
 8919        line_layouts: &[LineWithInvisibles],
 8920        line_height: Pixels,
 8921        scroll_pixel_position: gpui::Point<Pixels>,
 8922        newest_selection_head: Option<DisplayPoint>,
 8923        editor_width: Pixels,
 8924        style: &EditorStyle,
 8925        edits: &Vec<(Range<Anchor>, String)>,
 8926        edit_preview: &Option<language::EditPreview>,
 8927        snapshot: &language::BufferSnapshot,
 8928        window: &mut Window,
 8929        cx: &mut App,
 8930    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8931        let edit_start = edits
 8932            .first()
 8933            .unwrap()
 8934            .0
 8935            .start
 8936            .to_display_point(editor_snapshot);
 8937        let edit_end = edits
 8938            .last()
 8939            .unwrap()
 8940            .0
 8941            .end
 8942            .to_display_point(editor_snapshot);
 8943
 8944        let is_visible = visible_row_range.contains(&edit_start.row())
 8945            || visible_row_range.contains(&edit_end.row());
 8946        if !is_visible {
 8947            return None;
 8948        }
 8949
 8950        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8951            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8952        } else {
 8953            // Fallback for providers without edit_preview
 8954            crate::edit_prediction_fallback_text(edits, cx)
 8955        };
 8956
 8957        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8958        let line_count = highlighted_edits.text.lines().count();
 8959
 8960        const BORDER_WIDTH: Pixels = px(1.);
 8961
 8962        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8963        let has_keybind = keybind.is_some();
 8964
 8965        let mut element = h_flex()
 8966            .items_start()
 8967            .child(
 8968                h_flex()
 8969                    .bg(cx.theme().colors().editor_background)
 8970                    .border(BORDER_WIDTH)
 8971                    .shadow_xs()
 8972                    .border_color(cx.theme().colors().border)
 8973                    .rounded_l_lg()
 8974                    .when(line_count > 1, |el| el.rounded_br_lg())
 8975                    .pr_1()
 8976                    .child(styled_text),
 8977            )
 8978            .child(
 8979                h_flex()
 8980                    .h(line_height + BORDER_WIDTH * 2.)
 8981                    .px_1p5()
 8982                    .gap_1()
 8983                    // Workaround: For some reason, there's a gap if we don't do this
 8984                    .ml(-BORDER_WIDTH)
 8985                    .shadow(vec![gpui::BoxShadow {
 8986                        color: gpui::black().opacity(0.05),
 8987                        offset: point(px(1.), px(1.)),
 8988                        blur_radius: px(2.),
 8989                        spread_radius: px(0.),
 8990                    }])
 8991                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8992                    .border(BORDER_WIDTH)
 8993                    .border_color(cx.theme().colors().border)
 8994                    .rounded_r_lg()
 8995                    .id("edit_prediction_diff_popover_keybind")
 8996                    .when(!has_keybind, |el| {
 8997                        let status_colors = cx.theme().status();
 8998
 8999                        el.bg(status_colors.error_background)
 9000                            .border_color(status_colors.error.opacity(0.6))
 9001                            .child(Icon::new(IconName::Info).color(Color::Error))
 9002                            .cursor_default()
 9003                            .hoverable_tooltip(move |_window, cx| {
 9004                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9005                            })
 9006                    })
 9007                    .children(keybind),
 9008            )
 9009            .into_any();
 9010
 9011        let longest_row =
 9012            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9013        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9014            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9015        } else {
 9016            layout_line(
 9017                longest_row,
 9018                editor_snapshot,
 9019                style,
 9020                editor_width,
 9021                |_| false,
 9022                window,
 9023                cx,
 9024            )
 9025            .width
 9026        };
 9027
 9028        let viewport_bounds =
 9029            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9030                right: -right_margin,
 9031                ..Default::default()
 9032            });
 9033
 9034        let x_after_longest =
 9035            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9036                - scroll_pixel_position.x;
 9037
 9038        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9039
 9040        // Fully visible if it can be displayed within the window (allow overlapping other
 9041        // panes). However, this is only allowed if the popover starts within text_bounds.
 9042        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9043            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9044
 9045        let mut origin = if can_position_to_the_right {
 9046            point(
 9047                x_after_longest,
 9048                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9049                    - scroll_pixel_position.y,
 9050            )
 9051        } else {
 9052            let cursor_row = newest_selection_head.map(|head| head.row());
 9053            let above_edit = edit_start
 9054                .row()
 9055                .0
 9056                .checked_sub(line_count as u32)
 9057                .map(DisplayRow);
 9058            let below_edit = Some(edit_end.row() + 1);
 9059            let above_cursor =
 9060                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9061            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9062
 9063            // Place the edit popover adjacent to the edit if there is a location
 9064            // available that is onscreen and does not obscure the cursor. Otherwise,
 9065            // place it adjacent to the cursor.
 9066            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9067                .into_iter()
 9068                .flatten()
 9069                .find(|&start_row| {
 9070                    let end_row = start_row + line_count as u32;
 9071                    visible_row_range.contains(&start_row)
 9072                        && visible_row_range.contains(&end_row)
 9073                        && cursor_row
 9074                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9075                })?;
 9076
 9077            content_origin
 9078                + point(
 9079                    -scroll_pixel_position.x,
 9080                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9081                )
 9082        };
 9083
 9084        origin.x -= BORDER_WIDTH;
 9085
 9086        window.defer_draw(element, origin, 1);
 9087
 9088        // Do not return an element, since it will already be drawn due to defer_draw.
 9089        None
 9090    }
 9091
 9092    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9093        px(30.)
 9094    }
 9095
 9096    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9097        if self.read_only(cx) {
 9098            cx.theme().players().read_only()
 9099        } else {
 9100            self.style.as_ref().unwrap().local_player
 9101        }
 9102    }
 9103
 9104    fn render_edit_prediction_accept_keybind(
 9105        &self,
 9106        window: &mut Window,
 9107        cx: &App,
 9108    ) -> Option<AnyElement> {
 9109        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9110        let accept_keystroke = accept_binding.keystroke()?;
 9111
 9112        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9113
 9114        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9115            Color::Accent
 9116        } else {
 9117            Color::Muted
 9118        };
 9119
 9120        h_flex()
 9121            .px_0p5()
 9122            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9123            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9124            .text_size(TextSize::XSmall.rems(cx))
 9125            .child(h_flex().children(ui::render_modifiers(
 9126                accept_keystroke.modifiers(),
 9127                PlatformStyle::platform(),
 9128                Some(modifiers_color),
 9129                Some(IconSize::XSmall.rems().into()),
 9130                true,
 9131            )))
 9132            .when(is_platform_style_mac, |parent| {
 9133                parent.child(accept_keystroke.key().to_string())
 9134            })
 9135            .when(!is_platform_style_mac, |parent| {
 9136                parent.child(
 9137                    Key::new(
 9138                        util::capitalize(accept_keystroke.key()),
 9139                        Some(Color::Default),
 9140                    )
 9141                    .size(Some(IconSize::XSmall.rems().into())),
 9142                )
 9143            })
 9144            .into_any()
 9145            .into()
 9146    }
 9147
 9148    fn render_edit_prediction_line_popover(
 9149        &self,
 9150        label: impl Into<SharedString>,
 9151        icon: Option<IconName>,
 9152        window: &mut Window,
 9153        cx: &App,
 9154    ) -> Option<Stateful<Div>> {
 9155        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9156
 9157        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9158        let has_keybind = keybind.is_some();
 9159
 9160        let result = h_flex()
 9161            .id("ep-line-popover")
 9162            .py_0p5()
 9163            .pl_1()
 9164            .pr(padding_right)
 9165            .gap_1()
 9166            .rounded_md()
 9167            .border_1()
 9168            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9169            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9170            .shadow_xs()
 9171            .when(!has_keybind, |el| {
 9172                let status_colors = cx.theme().status();
 9173
 9174                el.bg(status_colors.error_background)
 9175                    .border_color(status_colors.error.opacity(0.6))
 9176                    .pl_2()
 9177                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9178                    .cursor_default()
 9179                    .hoverable_tooltip(move |_window, cx| {
 9180                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9181                    })
 9182            })
 9183            .children(keybind)
 9184            .child(
 9185                Label::new(label)
 9186                    .size(LabelSize::Small)
 9187                    .when(!has_keybind, |el| {
 9188                        el.color(cx.theme().status().error.into()).strikethrough()
 9189                    }),
 9190            )
 9191            .when(!has_keybind, |el| {
 9192                el.child(
 9193                    h_flex().ml_1().child(
 9194                        Icon::new(IconName::Info)
 9195                            .size(IconSize::Small)
 9196                            .color(cx.theme().status().error.into()),
 9197                    ),
 9198                )
 9199            })
 9200            .when_some(icon, |element, icon| {
 9201                element.child(
 9202                    div()
 9203                        .mt(px(1.5))
 9204                        .child(Icon::new(icon).size(IconSize::Small)),
 9205                )
 9206            });
 9207
 9208        Some(result)
 9209    }
 9210
 9211    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9212        let accent_color = cx.theme().colors().text_accent;
 9213        let editor_bg_color = cx.theme().colors().editor_background;
 9214        editor_bg_color.blend(accent_color.opacity(0.1))
 9215    }
 9216
 9217    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9218        let accent_color = cx.theme().colors().text_accent;
 9219        let editor_bg_color = cx.theme().colors().editor_background;
 9220        editor_bg_color.blend(accent_color.opacity(0.6))
 9221    }
 9222    fn get_prediction_provider_icon_name(
 9223        provider: &Option<RegisteredEditPredictionProvider>,
 9224    ) -> IconName {
 9225        match provider {
 9226            Some(provider) => match provider.provider.name() {
 9227                "copilot" => IconName::Copilot,
 9228                "supermaven" => IconName::Supermaven,
 9229                _ => IconName::ZedPredict,
 9230            },
 9231            None => IconName::ZedPredict,
 9232        }
 9233    }
 9234
 9235    fn render_edit_prediction_cursor_popover(
 9236        &self,
 9237        min_width: Pixels,
 9238        max_width: Pixels,
 9239        cursor_point: Point,
 9240        style: &EditorStyle,
 9241        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9242        _window: &Window,
 9243        cx: &mut Context<Editor>,
 9244    ) -> Option<AnyElement> {
 9245        let provider = self.edit_prediction_provider.as_ref()?;
 9246        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9247
 9248        let is_refreshing = provider.provider.is_refreshing(cx);
 9249
 9250        fn pending_completion_container(icon: IconName) -> Div {
 9251            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9252        }
 9253
 9254        let completion = match &self.active_edit_prediction {
 9255            Some(prediction) => {
 9256                if !self.has_visible_completions_menu() {
 9257                    const RADIUS: Pixels = px(6.);
 9258                    const BORDER_WIDTH: Pixels = px(1.);
 9259
 9260                    return Some(
 9261                        h_flex()
 9262                            .elevation_2(cx)
 9263                            .border(BORDER_WIDTH)
 9264                            .border_color(cx.theme().colors().border)
 9265                            .when(accept_keystroke.is_none(), |el| {
 9266                                el.border_color(cx.theme().status().error)
 9267                            })
 9268                            .rounded(RADIUS)
 9269                            .rounded_tl(px(0.))
 9270                            .overflow_hidden()
 9271                            .child(div().px_1p5().child(match &prediction.completion {
 9272                                EditPrediction::Move { target, snapshot } => {
 9273                                    use text::ToPoint as _;
 9274                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9275                                    {
 9276                                        Icon::new(IconName::ZedPredictDown)
 9277                                    } else {
 9278                                        Icon::new(IconName::ZedPredictUp)
 9279                                    }
 9280                                }
 9281                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9282                            }))
 9283                            .child(
 9284                                h_flex()
 9285                                    .gap_1()
 9286                                    .py_1()
 9287                                    .px_2()
 9288                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9289                                    .border_l_1()
 9290                                    .border_color(cx.theme().colors().border)
 9291                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9292                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9293                                        el.child(
 9294                                            Label::new("Hold")
 9295                                                .size(LabelSize::Small)
 9296                                                .when(accept_keystroke.is_none(), |el| {
 9297                                                    el.strikethrough()
 9298                                                })
 9299                                                .line_height_style(LineHeightStyle::UiLabel),
 9300                                        )
 9301                                    })
 9302                                    .id("edit_prediction_cursor_popover_keybind")
 9303                                    .when(accept_keystroke.is_none(), |el| {
 9304                                        let status_colors = cx.theme().status();
 9305
 9306                                        el.bg(status_colors.error_background)
 9307                                            .border_color(status_colors.error.opacity(0.6))
 9308                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9309                                            .cursor_default()
 9310                                            .hoverable_tooltip(move |_window, cx| {
 9311                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9312                                                    .into()
 9313                                            })
 9314                                    })
 9315                                    .when_some(
 9316                                        accept_keystroke.as_ref(),
 9317                                        |el, accept_keystroke| {
 9318                                            el.child(h_flex().children(ui::render_modifiers(
 9319                                                accept_keystroke.modifiers(),
 9320                                                PlatformStyle::platform(),
 9321                                                Some(Color::Default),
 9322                                                Some(IconSize::XSmall.rems().into()),
 9323                                                false,
 9324                                            )))
 9325                                        },
 9326                                    ),
 9327                            )
 9328                            .into_any(),
 9329                    );
 9330                }
 9331
 9332                self.render_edit_prediction_cursor_popover_preview(
 9333                    prediction,
 9334                    cursor_point,
 9335                    style,
 9336                    cx,
 9337                )?
 9338            }
 9339
 9340            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9341                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9342                    stale_completion,
 9343                    cursor_point,
 9344                    style,
 9345                    cx,
 9346                )?,
 9347
 9348                None => pending_completion_container(provider_icon)
 9349                    .child(Label::new("...").size(LabelSize::Small)),
 9350            },
 9351
 9352            None => pending_completion_container(provider_icon)
 9353                .child(Label::new("...").size(LabelSize::Small)),
 9354        };
 9355
 9356        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9357            completion
 9358                .with_animation(
 9359                    "loading-completion",
 9360                    Animation::new(Duration::from_secs(2))
 9361                        .repeat()
 9362                        .with_easing(pulsating_between(0.4, 0.8)),
 9363                    |label, delta| label.opacity(delta),
 9364                )
 9365                .into_any_element()
 9366        } else {
 9367            completion.into_any_element()
 9368        };
 9369
 9370        let has_completion = self.active_edit_prediction.is_some();
 9371
 9372        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9373        Some(
 9374            h_flex()
 9375                .min_w(min_width)
 9376                .max_w(max_width)
 9377                .flex_1()
 9378                .elevation_2(cx)
 9379                .border_color(cx.theme().colors().border)
 9380                .child(
 9381                    div()
 9382                        .flex_1()
 9383                        .py_1()
 9384                        .px_2()
 9385                        .overflow_hidden()
 9386                        .child(completion),
 9387                )
 9388                .when_some(accept_keystroke, |el, accept_keystroke| {
 9389                    if !accept_keystroke.modifiers().modified() {
 9390                        return el;
 9391                    }
 9392
 9393                    el.child(
 9394                        h_flex()
 9395                            .h_full()
 9396                            .border_l_1()
 9397                            .rounded_r_lg()
 9398                            .border_color(cx.theme().colors().border)
 9399                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9400                            .gap_1()
 9401                            .py_1()
 9402                            .px_2()
 9403                            .child(
 9404                                h_flex()
 9405                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9406                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9407                                    .child(h_flex().children(ui::render_modifiers(
 9408                                        accept_keystroke.modifiers(),
 9409                                        PlatformStyle::platform(),
 9410                                        Some(if !has_completion {
 9411                                            Color::Muted
 9412                                        } else {
 9413                                            Color::Default
 9414                                        }),
 9415                                        None,
 9416                                        false,
 9417                                    ))),
 9418                            )
 9419                            .child(Label::new("Preview").into_any_element())
 9420                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9421                    )
 9422                })
 9423                .into_any(),
 9424        )
 9425    }
 9426
 9427    fn render_edit_prediction_cursor_popover_preview(
 9428        &self,
 9429        completion: &EditPredictionState,
 9430        cursor_point: Point,
 9431        style: &EditorStyle,
 9432        cx: &mut Context<Editor>,
 9433    ) -> Option<Div> {
 9434        use text::ToPoint as _;
 9435
 9436        fn render_relative_row_jump(
 9437            prefix: impl Into<String>,
 9438            current_row: u32,
 9439            target_row: u32,
 9440        ) -> Div {
 9441            let (row_diff, arrow) = if target_row < current_row {
 9442                (current_row - target_row, IconName::ArrowUp)
 9443            } else {
 9444                (target_row - current_row, IconName::ArrowDown)
 9445            };
 9446
 9447            h_flex()
 9448                .child(
 9449                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9450                        .color(Color::Muted)
 9451                        .size(LabelSize::Small),
 9452                )
 9453                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9454        }
 9455
 9456        let supports_jump = self
 9457            .edit_prediction_provider
 9458            .as_ref()
 9459            .map(|provider| provider.provider.supports_jump_to_edit())
 9460            .unwrap_or(true);
 9461
 9462        match &completion.completion {
 9463            EditPrediction::Move {
 9464                target, snapshot, ..
 9465            } => {
 9466                if !supports_jump {
 9467                    return None;
 9468                }
 9469
 9470                Some(
 9471                    h_flex()
 9472                        .px_2()
 9473                        .gap_2()
 9474                        .flex_1()
 9475                        .child(
 9476                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9477                                Icon::new(IconName::ZedPredictDown)
 9478                            } else {
 9479                                Icon::new(IconName::ZedPredictUp)
 9480                            },
 9481                        )
 9482                        .child(Label::new("Jump to Edit")),
 9483                )
 9484            }
 9485
 9486            EditPrediction::Edit {
 9487                edits,
 9488                edit_preview,
 9489                snapshot,
 9490                display_mode: _,
 9491            } => {
 9492                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9493
 9494                let (highlighted_edits, has_more_lines) =
 9495                    if let Some(edit_preview) = edit_preview.as_ref() {
 9496                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9497                            .first_line_preview()
 9498                    } else {
 9499                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9500                    };
 9501
 9502                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9503                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9504
 9505                let preview = h_flex()
 9506                    .gap_1()
 9507                    .min_w_16()
 9508                    .child(styled_text)
 9509                    .when(has_more_lines, |parent| parent.child(""));
 9510
 9511                let left = if supports_jump && first_edit_row != cursor_point.row {
 9512                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9513                        .into_any_element()
 9514                } else {
 9515                    let icon_name =
 9516                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9517                    Icon::new(icon_name).into_any_element()
 9518                };
 9519
 9520                Some(
 9521                    h_flex()
 9522                        .h_full()
 9523                        .flex_1()
 9524                        .gap_2()
 9525                        .pr_1()
 9526                        .overflow_x_hidden()
 9527                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9528                        .child(left)
 9529                        .child(preview),
 9530                )
 9531            }
 9532        }
 9533    }
 9534
 9535    pub fn render_context_menu(
 9536        &self,
 9537        style: &EditorStyle,
 9538        max_height_in_lines: u32,
 9539        window: &mut Window,
 9540        cx: &mut Context<Editor>,
 9541    ) -> Option<AnyElement> {
 9542        let menu = self.context_menu.borrow();
 9543        let menu = menu.as_ref()?;
 9544        if !menu.visible() {
 9545            return None;
 9546        };
 9547        Some(menu.render(style, max_height_in_lines, window, cx))
 9548    }
 9549
 9550    fn render_context_menu_aside(
 9551        &mut self,
 9552        max_size: Size<Pixels>,
 9553        window: &mut Window,
 9554        cx: &mut Context<Editor>,
 9555    ) -> Option<AnyElement> {
 9556        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9557            if menu.visible() {
 9558                menu.render_aside(max_size, window, cx)
 9559            } else {
 9560                None
 9561            }
 9562        })
 9563    }
 9564
 9565    fn hide_context_menu(
 9566        &mut self,
 9567        window: &mut Window,
 9568        cx: &mut Context<Self>,
 9569    ) -> Option<CodeContextMenu> {
 9570        cx.notify();
 9571        self.completion_tasks.clear();
 9572        let context_menu = self.context_menu.borrow_mut().take();
 9573        self.stale_edit_prediction_in_menu.take();
 9574        self.update_visible_edit_prediction(window, cx);
 9575        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9576            && let Some(completion_provider) = &self.completion_provider
 9577        {
 9578            completion_provider.selection_changed(None, window, cx);
 9579        }
 9580        context_menu
 9581    }
 9582
 9583    fn show_snippet_choices(
 9584        &mut self,
 9585        choices: &Vec<String>,
 9586        selection: Range<Anchor>,
 9587        cx: &mut Context<Self>,
 9588    ) {
 9589        let Some((_, buffer, _)) = self
 9590            .buffer()
 9591            .read(cx)
 9592            .excerpt_containing(selection.start, cx)
 9593        else {
 9594            return;
 9595        };
 9596        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9597        else {
 9598            return;
 9599        };
 9600        if buffer != end_buffer {
 9601            log::error!("expected anchor range to have matching buffer IDs");
 9602            return;
 9603        }
 9604
 9605        let id = post_inc(&mut self.next_completion_id);
 9606        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9607        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9608            CompletionsMenu::new_snippet_choices(
 9609                id,
 9610                true,
 9611                choices,
 9612                selection,
 9613                buffer,
 9614                snippet_sort_order,
 9615            ),
 9616        ));
 9617    }
 9618
 9619    pub fn insert_snippet(
 9620        &mut self,
 9621        insertion_ranges: &[Range<usize>],
 9622        snippet: Snippet,
 9623        window: &mut Window,
 9624        cx: &mut Context<Self>,
 9625    ) -> Result<()> {
 9626        struct Tabstop<T> {
 9627            is_end_tabstop: bool,
 9628            ranges: Vec<Range<T>>,
 9629            choices: Option<Vec<String>>,
 9630        }
 9631
 9632        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9633            let snippet_text: Arc<str> = snippet.text.clone().into();
 9634            let edits = insertion_ranges
 9635                .iter()
 9636                .cloned()
 9637                .map(|range| (range, snippet_text.clone()));
 9638            let autoindent_mode = AutoindentMode::Block {
 9639                original_indent_columns: Vec::new(),
 9640            };
 9641            buffer.edit(edits, Some(autoindent_mode), cx);
 9642
 9643            let snapshot = &*buffer.read(cx);
 9644            let snippet = &snippet;
 9645            snippet
 9646                .tabstops
 9647                .iter()
 9648                .map(|tabstop| {
 9649                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9650                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9651                    });
 9652                    let mut tabstop_ranges = tabstop
 9653                        .ranges
 9654                        .iter()
 9655                        .flat_map(|tabstop_range| {
 9656                            let mut delta = 0_isize;
 9657                            insertion_ranges.iter().map(move |insertion_range| {
 9658                                let insertion_start = insertion_range.start as isize + delta;
 9659                                delta +=
 9660                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9661
 9662                                let start = ((insertion_start + tabstop_range.start) as usize)
 9663                                    .min(snapshot.len());
 9664                                let end = ((insertion_start + tabstop_range.end) as usize)
 9665                                    .min(snapshot.len());
 9666                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9667                            })
 9668                        })
 9669                        .collect::<Vec<_>>();
 9670                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9671
 9672                    Tabstop {
 9673                        is_end_tabstop,
 9674                        ranges: tabstop_ranges,
 9675                        choices: tabstop.choices.clone(),
 9676                    }
 9677                })
 9678                .collect::<Vec<_>>()
 9679        });
 9680        if let Some(tabstop) = tabstops.first() {
 9681            self.change_selections(Default::default(), window, cx, |s| {
 9682                // Reverse order so that the first range is the newest created selection.
 9683                // Completions will use it and autoscroll will prioritize it.
 9684                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9685            });
 9686
 9687            if let Some(choices) = &tabstop.choices
 9688                && let Some(selection) = tabstop.ranges.first()
 9689            {
 9690                self.show_snippet_choices(choices, selection.clone(), cx)
 9691            }
 9692
 9693            // If we're already at the last tabstop and it's at the end of the snippet,
 9694            // we're done, we don't need to keep the state around.
 9695            if !tabstop.is_end_tabstop {
 9696                let choices = tabstops
 9697                    .iter()
 9698                    .map(|tabstop| tabstop.choices.clone())
 9699                    .collect();
 9700
 9701                let ranges = tabstops
 9702                    .into_iter()
 9703                    .map(|tabstop| tabstop.ranges)
 9704                    .collect::<Vec<_>>();
 9705
 9706                self.snippet_stack.push(SnippetState {
 9707                    active_index: 0,
 9708                    ranges,
 9709                    choices,
 9710                });
 9711            }
 9712
 9713            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9714            if self.autoclose_regions.is_empty() {
 9715                let snapshot = self.buffer.read(cx).snapshot(cx);
 9716                let mut all_selections = self.selections.all::<Point>(cx);
 9717                for selection in &mut all_selections {
 9718                    let selection_head = selection.head();
 9719                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9720                        continue;
 9721                    };
 9722
 9723                    let mut bracket_pair = None;
 9724                    let max_lookup_length = scope
 9725                        .brackets()
 9726                        .map(|(pair, _)| {
 9727                            pair.start
 9728                                .as_str()
 9729                                .chars()
 9730                                .count()
 9731                                .max(pair.end.as_str().chars().count())
 9732                        })
 9733                        .max();
 9734                    if let Some(max_lookup_length) = max_lookup_length {
 9735                        let next_text = snapshot
 9736                            .chars_at(selection_head)
 9737                            .take(max_lookup_length)
 9738                            .collect::<String>();
 9739                        let prev_text = snapshot
 9740                            .reversed_chars_at(selection_head)
 9741                            .take(max_lookup_length)
 9742                            .collect::<String>();
 9743
 9744                        for (pair, enabled) in scope.brackets() {
 9745                            if enabled
 9746                                && pair.close
 9747                                && prev_text.starts_with(pair.start.as_str())
 9748                                && next_text.starts_with(pair.end.as_str())
 9749                            {
 9750                                bracket_pair = Some(pair.clone());
 9751                                break;
 9752                            }
 9753                        }
 9754                    }
 9755
 9756                    if let Some(pair) = bracket_pair {
 9757                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9758                        let autoclose_enabled =
 9759                            self.use_autoclose && snapshot_settings.use_autoclose;
 9760                        if autoclose_enabled {
 9761                            let start = snapshot.anchor_after(selection_head);
 9762                            let end = snapshot.anchor_after(selection_head);
 9763                            self.autoclose_regions.push(AutocloseRegion {
 9764                                selection_id: selection.id,
 9765                                range: start..end,
 9766                                pair,
 9767                            });
 9768                        }
 9769                    }
 9770                }
 9771            }
 9772        }
 9773        Ok(())
 9774    }
 9775
 9776    pub fn move_to_next_snippet_tabstop(
 9777        &mut self,
 9778        window: &mut Window,
 9779        cx: &mut Context<Self>,
 9780    ) -> bool {
 9781        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9782    }
 9783
 9784    pub fn move_to_prev_snippet_tabstop(
 9785        &mut self,
 9786        window: &mut Window,
 9787        cx: &mut Context<Self>,
 9788    ) -> bool {
 9789        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9790    }
 9791
 9792    pub fn move_to_snippet_tabstop(
 9793        &mut self,
 9794        bias: Bias,
 9795        window: &mut Window,
 9796        cx: &mut Context<Self>,
 9797    ) -> bool {
 9798        if let Some(mut snippet) = self.snippet_stack.pop() {
 9799            match bias {
 9800                Bias::Left => {
 9801                    if snippet.active_index > 0 {
 9802                        snippet.active_index -= 1;
 9803                    } else {
 9804                        self.snippet_stack.push(snippet);
 9805                        return false;
 9806                    }
 9807                }
 9808                Bias::Right => {
 9809                    if snippet.active_index + 1 < snippet.ranges.len() {
 9810                        snippet.active_index += 1;
 9811                    } else {
 9812                        self.snippet_stack.push(snippet);
 9813                        return false;
 9814                    }
 9815                }
 9816            }
 9817            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9818                self.change_selections(Default::default(), window, cx, |s| {
 9819                    // Reverse order so that the first range is the newest created selection.
 9820                    // Completions will use it and autoscroll will prioritize it.
 9821                    s.select_ranges(current_ranges.iter().rev().cloned())
 9822                });
 9823
 9824                if let Some(choices) = &snippet.choices[snippet.active_index]
 9825                    && let Some(selection) = current_ranges.first()
 9826                {
 9827                    self.show_snippet_choices(choices, selection.clone(), cx);
 9828                }
 9829
 9830                // If snippet state is not at the last tabstop, push it back on the stack
 9831                if snippet.active_index + 1 < snippet.ranges.len() {
 9832                    self.snippet_stack.push(snippet);
 9833                }
 9834                return true;
 9835            }
 9836        }
 9837
 9838        false
 9839    }
 9840
 9841    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9842        self.transact(window, cx, |this, window, cx| {
 9843            this.select_all(&SelectAll, window, cx);
 9844            this.insert("", window, cx);
 9845        });
 9846    }
 9847
 9848    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9849        if self.read_only(cx) {
 9850            return;
 9851        }
 9852        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9853        self.transact(window, cx, |this, window, cx| {
 9854            this.select_autoclose_pair(window, cx);
 9855            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9856            if !this.linked_edit_ranges.is_empty() {
 9857                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9858                let snapshot = this.buffer.read(cx).snapshot(cx);
 9859
 9860                for selection in selections.iter() {
 9861                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9862                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9863                    if selection_start.buffer_id != selection_end.buffer_id {
 9864                        continue;
 9865                    }
 9866                    if let Some(ranges) =
 9867                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9868                    {
 9869                        for (buffer, entries) in ranges {
 9870                            linked_ranges.entry(buffer).or_default().extend(entries);
 9871                        }
 9872                    }
 9873                }
 9874            }
 9875
 9876            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9877            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9878            for selection in &mut selections {
 9879                if selection.is_empty() {
 9880                    let old_head = selection.head();
 9881                    let mut new_head =
 9882                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9883                            .to_point(&display_map);
 9884                    if let Some((buffer, line_buffer_range)) = display_map
 9885                        .buffer_snapshot
 9886                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9887                    {
 9888                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9889                        let indent_len = match indent_size.kind {
 9890                            IndentKind::Space => {
 9891                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9892                            }
 9893                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9894                        };
 9895                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9896                            let indent_len = indent_len.get();
 9897                            new_head = cmp::min(
 9898                                new_head,
 9899                                MultiBufferPoint::new(
 9900                                    old_head.row,
 9901                                    ((old_head.column - 1) / indent_len) * indent_len,
 9902                                ),
 9903                            );
 9904                        }
 9905                    }
 9906
 9907                    selection.set_head(new_head, SelectionGoal::None);
 9908                }
 9909            }
 9910
 9911            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9912            this.insert("", window, cx);
 9913            let empty_str: Arc<str> = Arc::from("");
 9914            for (buffer, edits) in linked_ranges {
 9915                let snapshot = buffer.read(cx).snapshot();
 9916                use text::ToPoint as TP;
 9917
 9918                let edits = edits
 9919                    .into_iter()
 9920                    .map(|range| {
 9921                        let end_point = TP::to_point(&range.end, &snapshot);
 9922                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9923
 9924                        if end_point == start_point {
 9925                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9926                                .saturating_sub(1);
 9927                            start_point =
 9928                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9929                        };
 9930
 9931                        (start_point..end_point, empty_str.clone())
 9932                    })
 9933                    .sorted_by_key(|(range, _)| range.start)
 9934                    .collect::<Vec<_>>();
 9935                buffer.update(cx, |this, cx| {
 9936                    this.edit(edits, None, cx);
 9937                })
 9938            }
 9939            this.refresh_edit_prediction(true, false, window, cx);
 9940            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9941        });
 9942    }
 9943
 9944    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9945        if self.read_only(cx) {
 9946            return;
 9947        }
 9948        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9949        self.transact(window, cx, |this, window, cx| {
 9950            this.change_selections(Default::default(), window, cx, |s| {
 9951                s.move_with(|map, selection| {
 9952                    if selection.is_empty() {
 9953                        let cursor = movement::right(map, selection.head());
 9954                        selection.end = cursor;
 9955                        selection.reversed = true;
 9956                        selection.goal = SelectionGoal::None;
 9957                    }
 9958                })
 9959            });
 9960            this.insert("", window, cx);
 9961            this.refresh_edit_prediction(true, false, window, cx);
 9962        });
 9963    }
 9964
 9965    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9966        if self.mode.is_single_line() {
 9967            cx.propagate();
 9968            return;
 9969        }
 9970
 9971        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9972        if self.move_to_prev_snippet_tabstop(window, cx) {
 9973            return;
 9974        }
 9975        self.outdent(&Outdent, window, cx);
 9976    }
 9977
 9978    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9979        if self.mode.is_single_line() {
 9980            cx.propagate();
 9981            return;
 9982        }
 9983
 9984        if self.move_to_next_snippet_tabstop(window, cx) {
 9985            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9986            return;
 9987        }
 9988        if self.read_only(cx) {
 9989            return;
 9990        }
 9991        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9992        let mut selections = self.selections.all_adjusted(cx);
 9993        let buffer = self.buffer.read(cx);
 9994        let snapshot = buffer.snapshot(cx);
 9995        let rows_iter = selections.iter().map(|s| s.head().row);
 9996        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9997
 9998        let has_some_cursor_in_whitespace = selections
 9999            .iter()
10000            .filter(|selection| selection.is_empty())
10001            .any(|selection| {
10002                let cursor = selection.head();
10003                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10004                cursor.column < current_indent.len
10005            });
10006
10007        let mut edits = Vec::new();
10008        let mut prev_edited_row = 0;
10009        let mut row_delta = 0;
10010        for selection in &mut selections {
10011            if selection.start.row != prev_edited_row {
10012                row_delta = 0;
10013            }
10014            prev_edited_row = selection.end.row;
10015
10016            // If the selection is non-empty, then increase the indentation of the selected lines.
10017            if !selection.is_empty() {
10018                row_delta =
10019                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10020                continue;
10021            }
10022
10023            let cursor = selection.head();
10024            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10025            if let Some(suggested_indent) =
10026                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10027            {
10028                // Don't do anything if already at suggested indent
10029                // and there is any other cursor which is not
10030                if has_some_cursor_in_whitespace
10031                    && cursor.column == current_indent.len
10032                    && current_indent.len == suggested_indent.len
10033                {
10034                    continue;
10035                }
10036
10037                // Adjust line and move cursor to suggested indent
10038                // if cursor is not at suggested indent
10039                if cursor.column < suggested_indent.len
10040                    && cursor.column <= current_indent.len
10041                    && current_indent.len <= suggested_indent.len
10042                {
10043                    selection.start = Point::new(cursor.row, suggested_indent.len);
10044                    selection.end = selection.start;
10045                    if row_delta == 0 {
10046                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10047                            cursor.row,
10048                            current_indent,
10049                            suggested_indent,
10050                        ));
10051                        row_delta = suggested_indent.len - current_indent.len;
10052                    }
10053                    continue;
10054                }
10055
10056                // If current indent is more than suggested indent
10057                // only move cursor to current indent and skip indent
10058                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10059                    selection.start = Point::new(cursor.row, current_indent.len);
10060                    selection.end = selection.start;
10061                    continue;
10062                }
10063            }
10064
10065            // Otherwise, insert a hard or soft tab.
10066            let settings = buffer.language_settings_at(cursor, cx);
10067            let tab_size = if settings.hard_tabs {
10068                IndentSize::tab()
10069            } else {
10070                let tab_size = settings.tab_size.get();
10071                let indent_remainder = snapshot
10072                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10073                    .flat_map(str::chars)
10074                    .fold(row_delta % tab_size, |counter: u32, c| {
10075                        if c == '\t' {
10076                            0
10077                        } else {
10078                            (counter + 1) % tab_size
10079                        }
10080                    });
10081
10082                let chars_to_next_tab_stop = tab_size - indent_remainder;
10083                IndentSize::spaces(chars_to_next_tab_stop)
10084            };
10085            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10086            selection.end = selection.start;
10087            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10088            row_delta += tab_size.len;
10089        }
10090
10091        self.transact(window, cx, |this, window, cx| {
10092            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10093            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10094            this.refresh_edit_prediction(true, false, window, cx);
10095        });
10096    }
10097
10098    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10099        if self.read_only(cx) {
10100            return;
10101        }
10102        if self.mode.is_single_line() {
10103            cx.propagate();
10104            return;
10105        }
10106
10107        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10108        let mut selections = self.selections.all::<Point>(cx);
10109        let mut prev_edited_row = 0;
10110        let mut row_delta = 0;
10111        let mut edits = Vec::new();
10112        let buffer = self.buffer.read(cx);
10113        let snapshot = buffer.snapshot(cx);
10114        for selection in &mut selections {
10115            if selection.start.row != prev_edited_row {
10116                row_delta = 0;
10117            }
10118            prev_edited_row = selection.end.row;
10119
10120            row_delta =
10121                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10122        }
10123
10124        self.transact(window, cx, |this, window, cx| {
10125            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10126            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10127        });
10128    }
10129
10130    fn indent_selection(
10131        buffer: &MultiBuffer,
10132        snapshot: &MultiBufferSnapshot,
10133        selection: &mut Selection<Point>,
10134        edits: &mut Vec<(Range<Point>, String)>,
10135        delta_for_start_row: u32,
10136        cx: &App,
10137    ) -> u32 {
10138        let settings = buffer.language_settings_at(selection.start, cx);
10139        let tab_size = settings.tab_size.get();
10140        let indent_kind = if settings.hard_tabs {
10141            IndentKind::Tab
10142        } else {
10143            IndentKind::Space
10144        };
10145        let mut start_row = selection.start.row;
10146        let mut end_row = selection.end.row + 1;
10147
10148        // If a selection ends at the beginning of a line, don't indent
10149        // that last line.
10150        if selection.end.column == 0 && selection.end.row > selection.start.row {
10151            end_row -= 1;
10152        }
10153
10154        // Avoid re-indenting a row that has already been indented by a
10155        // previous selection, but still update this selection's column
10156        // to reflect that indentation.
10157        if delta_for_start_row > 0 {
10158            start_row += 1;
10159            selection.start.column += delta_for_start_row;
10160            if selection.end.row == selection.start.row {
10161                selection.end.column += delta_for_start_row;
10162            }
10163        }
10164
10165        let mut delta_for_end_row = 0;
10166        let has_multiple_rows = start_row + 1 != end_row;
10167        for row in start_row..end_row {
10168            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10169            let indent_delta = match (current_indent.kind, indent_kind) {
10170                (IndentKind::Space, IndentKind::Space) => {
10171                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10172                    IndentSize::spaces(columns_to_next_tab_stop)
10173                }
10174                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10175                (_, IndentKind::Tab) => IndentSize::tab(),
10176            };
10177
10178            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10179                0
10180            } else {
10181                selection.start.column
10182            };
10183            let row_start = Point::new(row, start);
10184            edits.push((
10185                row_start..row_start,
10186                indent_delta.chars().collect::<String>(),
10187            ));
10188
10189            // Update this selection's endpoints to reflect the indentation.
10190            if row == selection.start.row {
10191                selection.start.column += indent_delta.len;
10192            }
10193            if row == selection.end.row {
10194                selection.end.column += indent_delta.len;
10195                delta_for_end_row = indent_delta.len;
10196            }
10197        }
10198
10199        if selection.start.row == selection.end.row {
10200            delta_for_start_row + delta_for_end_row
10201        } else {
10202            delta_for_end_row
10203        }
10204    }
10205
10206    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10207        if self.read_only(cx) {
10208            return;
10209        }
10210        if self.mode.is_single_line() {
10211            cx.propagate();
10212            return;
10213        }
10214
10215        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10216        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10217        let selections = self.selections.all::<Point>(cx);
10218        let mut deletion_ranges = Vec::new();
10219        let mut last_outdent = None;
10220        {
10221            let buffer = self.buffer.read(cx);
10222            let snapshot = buffer.snapshot(cx);
10223            for selection in &selections {
10224                let settings = buffer.language_settings_at(selection.start, cx);
10225                let tab_size = settings.tab_size.get();
10226                let mut rows = selection.spanned_rows(false, &display_map);
10227
10228                // Avoid re-outdenting a row that has already been outdented by a
10229                // previous selection.
10230                if let Some(last_row) = last_outdent
10231                    && last_row == rows.start
10232                {
10233                    rows.start = rows.start.next_row();
10234                }
10235                let has_multiple_rows = rows.len() > 1;
10236                for row in rows.iter_rows() {
10237                    let indent_size = snapshot.indent_size_for_line(row);
10238                    if indent_size.len > 0 {
10239                        let deletion_len = match indent_size.kind {
10240                            IndentKind::Space => {
10241                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10242                                if columns_to_prev_tab_stop == 0 {
10243                                    tab_size
10244                                } else {
10245                                    columns_to_prev_tab_stop
10246                                }
10247                            }
10248                            IndentKind::Tab => 1,
10249                        };
10250                        let start = if has_multiple_rows
10251                            || deletion_len > selection.start.column
10252                            || indent_size.len < selection.start.column
10253                        {
10254                            0
10255                        } else {
10256                            selection.start.column - deletion_len
10257                        };
10258                        deletion_ranges.push(
10259                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10260                        );
10261                        last_outdent = Some(row);
10262                    }
10263                }
10264            }
10265        }
10266
10267        self.transact(window, cx, |this, window, cx| {
10268            this.buffer.update(cx, |buffer, cx| {
10269                let empty_str: Arc<str> = Arc::default();
10270                buffer.edit(
10271                    deletion_ranges
10272                        .into_iter()
10273                        .map(|range| (range, empty_str.clone())),
10274                    None,
10275                    cx,
10276                );
10277            });
10278            let selections = this.selections.all::<usize>(cx);
10279            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10280        });
10281    }
10282
10283    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10284        if self.read_only(cx) {
10285            return;
10286        }
10287        if self.mode.is_single_line() {
10288            cx.propagate();
10289            return;
10290        }
10291
10292        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10293        let selections = self
10294            .selections
10295            .all::<usize>(cx)
10296            .into_iter()
10297            .map(|s| s.range());
10298
10299        self.transact(window, cx, |this, window, cx| {
10300            this.buffer.update(cx, |buffer, cx| {
10301                buffer.autoindent_ranges(selections, cx);
10302            });
10303            let selections = this.selections.all::<usize>(cx);
10304            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10305        });
10306    }
10307
10308    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10310        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10311        let selections = self.selections.all::<Point>(cx);
10312
10313        let mut new_cursors = Vec::new();
10314        let mut edit_ranges = Vec::new();
10315        let mut selections = selections.iter().peekable();
10316        while let Some(selection) = selections.next() {
10317            let mut rows = selection.spanned_rows(false, &display_map);
10318            let goal_display_column = selection.head().to_display_point(&display_map).column();
10319
10320            // Accumulate contiguous regions of rows that we want to delete.
10321            while let Some(next_selection) = selections.peek() {
10322                let next_rows = next_selection.spanned_rows(false, &display_map);
10323                if next_rows.start <= rows.end {
10324                    rows.end = next_rows.end;
10325                    selections.next().unwrap();
10326                } else {
10327                    break;
10328                }
10329            }
10330
10331            let buffer = &display_map.buffer_snapshot;
10332            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10333            let edit_end;
10334            let cursor_buffer_row;
10335            if buffer.max_point().row >= rows.end.0 {
10336                // If there's a line after the range, delete the \n from the end of the row range
10337                // and position the cursor on the next line.
10338                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10339                cursor_buffer_row = rows.end;
10340            } else {
10341                // If there isn't a line after the range, delete the \n from the line before the
10342                // start of the row range and position the cursor there.
10343                edit_start = edit_start.saturating_sub(1);
10344                edit_end = buffer.len();
10345                cursor_buffer_row = rows.start.previous_row();
10346            }
10347
10348            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10349            *cursor.column_mut() =
10350                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10351
10352            new_cursors.push((
10353                selection.id,
10354                buffer.anchor_after(cursor.to_point(&display_map)),
10355            ));
10356            edit_ranges.push(edit_start..edit_end);
10357        }
10358
10359        self.transact(window, cx, |this, window, cx| {
10360            let buffer = this.buffer.update(cx, |buffer, cx| {
10361                let empty_str: Arc<str> = Arc::default();
10362                buffer.edit(
10363                    edit_ranges
10364                        .into_iter()
10365                        .map(|range| (range, empty_str.clone())),
10366                    None,
10367                    cx,
10368                );
10369                buffer.snapshot(cx)
10370            });
10371            let new_selections = new_cursors
10372                .into_iter()
10373                .map(|(id, cursor)| {
10374                    let cursor = cursor.to_point(&buffer);
10375                    Selection {
10376                        id,
10377                        start: cursor,
10378                        end: cursor,
10379                        reversed: false,
10380                        goal: SelectionGoal::None,
10381                    }
10382                })
10383                .collect();
10384
10385            this.change_selections(Default::default(), window, cx, |s| {
10386                s.select(new_selections);
10387            });
10388        });
10389    }
10390
10391    pub fn join_lines_impl(
10392        &mut self,
10393        insert_whitespace: bool,
10394        window: &mut Window,
10395        cx: &mut Context<Self>,
10396    ) {
10397        if self.read_only(cx) {
10398            return;
10399        }
10400        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10401        for selection in self.selections.all::<Point>(cx) {
10402            let start = MultiBufferRow(selection.start.row);
10403            // Treat single line selections as if they include the next line. Otherwise this action
10404            // would do nothing for single line selections individual cursors.
10405            let end = if selection.start.row == selection.end.row {
10406                MultiBufferRow(selection.start.row + 1)
10407            } else {
10408                MultiBufferRow(selection.end.row)
10409            };
10410
10411            if let Some(last_row_range) = row_ranges.last_mut()
10412                && start <= last_row_range.end
10413            {
10414                last_row_range.end = end;
10415                continue;
10416            }
10417            row_ranges.push(start..end);
10418        }
10419
10420        let snapshot = self.buffer.read(cx).snapshot(cx);
10421        let mut cursor_positions = Vec::new();
10422        for row_range in &row_ranges {
10423            let anchor = snapshot.anchor_before(Point::new(
10424                row_range.end.previous_row().0,
10425                snapshot.line_len(row_range.end.previous_row()),
10426            ));
10427            cursor_positions.push(anchor..anchor);
10428        }
10429
10430        self.transact(window, cx, |this, window, cx| {
10431            for row_range in row_ranges.into_iter().rev() {
10432                for row in row_range.iter_rows().rev() {
10433                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10434                    let next_line_row = row.next_row();
10435                    let indent = snapshot.indent_size_for_line(next_line_row);
10436                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10437
10438                    let replace =
10439                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10440                            " "
10441                        } else {
10442                            ""
10443                        };
10444
10445                    this.buffer.update(cx, |buffer, cx| {
10446                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10447                    });
10448                }
10449            }
10450
10451            this.change_selections(Default::default(), window, cx, |s| {
10452                s.select_anchor_ranges(cursor_positions)
10453            });
10454        });
10455    }
10456
10457    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10458        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10459        self.join_lines_impl(true, window, cx);
10460    }
10461
10462    pub fn sort_lines_case_sensitive(
10463        &mut self,
10464        _: &SortLinesCaseSensitive,
10465        window: &mut Window,
10466        cx: &mut Context<Self>,
10467    ) {
10468        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10469    }
10470
10471    pub fn sort_lines_by_length(
10472        &mut self,
10473        _: &SortLinesByLength,
10474        window: &mut Window,
10475        cx: &mut Context<Self>,
10476    ) {
10477        self.manipulate_immutable_lines(window, cx, |lines| {
10478            lines.sort_by_key(|&line| line.chars().count())
10479        })
10480    }
10481
10482    pub fn sort_lines_case_insensitive(
10483        &mut self,
10484        _: &SortLinesCaseInsensitive,
10485        window: &mut Window,
10486        cx: &mut Context<Self>,
10487    ) {
10488        self.manipulate_immutable_lines(window, cx, |lines| {
10489            lines.sort_by_key(|line| line.to_lowercase())
10490        })
10491    }
10492
10493    pub fn unique_lines_case_insensitive(
10494        &mut self,
10495        _: &UniqueLinesCaseInsensitive,
10496        window: &mut Window,
10497        cx: &mut Context<Self>,
10498    ) {
10499        self.manipulate_immutable_lines(window, cx, |lines| {
10500            let mut seen = HashSet::default();
10501            lines.retain(|line| seen.insert(line.to_lowercase()));
10502        })
10503    }
10504
10505    pub fn unique_lines_case_sensitive(
10506        &mut self,
10507        _: &UniqueLinesCaseSensitive,
10508        window: &mut Window,
10509        cx: &mut Context<Self>,
10510    ) {
10511        self.manipulate_immutable_lines(window, cx, |lines| {
10512            let mut seen = HashSet::default();
10513            lines.retain(|line| seen.insert(*line));
10514        })
10515    }
10516
10517    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10518        let snapshot = self.buffer.read(cx).snapshot(cx);
10519        for selection in self.selections.disjoint_anchors_arc().iter() {
10520            if snapshot
10521                .language_at(selection.start)
10522                .and_then(|lang| lang.config().wrap_characters.as_ref())
10523                .is_some()
10524            {
10525                return true;
10526            }
10527        }
10528        false
10529    }
10530
10531    fn wrap_selections_in_tag(
10532        &mut self,
10533        _: &WrapSelectionsInTag,
10534        window: &mut Window,
10535        cx: &mut Context<Self>,
10536    ) {
10537        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10538
10539        let snapshot = self.buffer.read(cx).snapshot(cx);
10540
10541        let mut edits = Vec::new();
10542        let mut boundaries = Vec::new();
10543
10544        for selection in self.selections.all::<Point>(cx).iter() {
10545            let Some(wrap_config) = snapshot
10546                .language_at(selection.start)
10547                .and_then(|lang| lang.config().wrap_characters.clone())
10548            else {
10549                continue;
10550            };
10551
10552            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10553            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10554
10555            let start_before = snapshot.anchor_before(selection.start);
10556            let end_after = snapshot.anchor_after(selection.end);
10557
10558            edits.push((start_before..start_before, open_tag));
10559            edits.push((end_after..end_after, close_tag));
10560
10561            boundaries.push((
10562                start_before,
10563                end_after,
10564                wrap_config.start_prefix.len(),
10565                wrap_config.end_suffix.len(),
10566            ));
10567        }
10568
10569        if edits.is_empty() {
10570            return;
10571        }
10572
10573        self.transact(window, cx, |this, window, cx| {
10574            let buffer = this.buffer.update(cx, |buffer, cx| {
10575                buffer.edit(edits, None, cx);
10576                buffer.snapshot(cx)
10577            });
10578
10579            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10580            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10581                boundaries.into_iter()
10582            {
10583                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10584                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10585                new_selections.push(open_offset..open_offset);
10586                new_selections.push(close_offset..close_offset);
10587            }
10588
10589            this.change_selections(Default::default(), window, cx, |s| {
10590                s.select_ranges(new_selections);
10591            });
10592
10593            this.request_autoscroll(Autoscroll::fit(), cx);
10594        });
10595    }
10596
10597    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10598        let Some(project) = self.project.clone() else {
10599            return;
10600        };
10601        self.reload(project, window, cx)
10602            .detach_and_notify_err(window, cx);
10603    }
10604
10605    pub fn restore_file(
10606        &mut self,
10607        _: &::git::RestoreFile,
10608        window: &mut Window,
10609        cx: &mut Context<Self>,
10610    ) {
10611        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10612        let mut buffer_ids = HashSet::default();
10613        let snapshot = self.buffer().read(cx).snapshot(cx);
10614        for selection in self.selections.all::<usize>(cx) {
10615            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10616        }
10617
10618        let buffer = self.buffer().read(cx);
10619        let ranges = buffer_ids
10620            .into_iter()
10621            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10622            .collect::<Vec<_>>();
10623
10624        self.restore_hunks_in_ranges(ranges, window, cx);
10625    }
10626
10627    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10628        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10629        let selections = self
10630            .selections
10631            .all(cx)
10632            .into_iter()
10633            .map(|s| s.range())
10634            .collect();
10635        self.restore_hunks_in_ranges(selections, window, cx);
10636    }
10637
10638    pub fn restore_hunks_in_ranges(
10639        &mut self,
10640        ranges: Vec<Range<Point>>,
10641        window: &mut Window,
10642        cx: &mut Context<Editor>,
10643    ) {
10644        let mut revert_changes = HashMap::default();
10645        let chunk_by = self
10646            .snapshot(window, cx)
10647            .hunks_for_ranges(ranges)
10648            .into_iter()
10649            .chunk_by(|hunk| hunk.buffer_id);
10650        for (buffer_id, hunks) in &chunk_by {
10651            let hunks = hunks.collect::<Vec<_>>();
10652            for hunk in &hunks {
10653                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10654            }
10655            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10656        }
10657        drop(chunk_by);
10658        if !revert_changes.is_empty() {
10659            self.transact(window, cx, |editor, window, cx| {
10660                editor.restore(revert_changes, window, cx);
10661            });
10662        }
10663    }
10664
10665    pub fn open_active_item_in_terminal(
10666        &mut self,
10667        _: &OpenInTerminal,
10668        window: &mut Window,
10669        cx: &mut Context<Self>,
10670    ) {
10671        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10672            let project_path = buffer.read(cx).project_path(cx)?;
10673            let project = self.project()?.read(cx);
10674            let entry = project.entry_for_path(&project_path, cx)?;
10675            let parent = match &entry.canonical_path {
10676                Some(canonical_path) => canonical_path.to_path_buf(),
10677                None => project.absolute_path(&project_path, cx)?,
10678            }
10679            .parent()?
10680            .to_path_buf();
10681            Some(parent)
10682        }) {
10683            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10684        }
10685    }
10686
10687    fn set_breakpoint_context_menu(
10688        &mut self,
10689        display_row: DisplayRow,
10690        position: Option<Anchor>,
10691        clicked_point: gpui::Point<Pixels>,
10692        window: &mut Window,
10693        cx: &mut Context<Self>,
10694    ) {
10695        let source = self
10696            .buffer
10697            .read(cx)
10698            .snapshot(cx)
10699            .anchor_before(Point::new(display_row.0, 0u32));
10700
10701        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10702
10703        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10704            self,
10705            source,
10706            clicked_point,
10707            context_menu,
10708            window,
10709            cx,
10710        );
10711    }
10712
10713    fn add_edit_breakpoint_block(
10714        &mut self,
10715        anchor: Anchor,
10716        breakpoint: &Breakpoint,
10717        edit_action: BreakpointPromptEditAction,
10718        window: &mut Window,
10719        cx: &mut Context<Self>,
10720    ) {
10721        let weak_editor = cx.weak_entity();
10722        let bp_prompt = cx.new(|cx| {
10723            BreakpointPromptEditor::new(
10724                weak_editor,
10725                anchor,
10726                breakpoint.clone(),
10727                edit_action,
10728                window,
10729                cx,
10730            )
10731        });
10732
10733        let height = bp_prompt.update(cx, |this, cx| {
10734            this.prompt
10735                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10736        });
10737        let cloned_prompt = bp_prompt.clone();
10738        let blocks = vec![BlockProperties {
10739            style: BlockStyle::Sticky,
10740            placement: BlockPlacement::Above(anchor),
10741            height: Some(height),
10742            render: Arc::new(move |cx| {
10743                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10744                cloned_prompt.clone().into_any_element()
10745            }),
10746            priority: 0,
10747        }];
10748
10749        let focus_handle = bp_prompt.focus_handle(cx);
10750        window.focus(&focus_handle);
10751
10752        let block_ids = self.insert_blocks(blocks, None, cx);
10753        bp_prompt.update(cx, |prompt, _| {
10754            prompt.add_block_ids(block_ids);
10755        });
10756    }
10757
10758    pub(crate) fn breakpoint_at_row(
10759        &self,
10760        row: u32,
10761        window: &mut Window,
10762        cx: &mut Context<Self>,
10763    ) -> Option<(Anchor, Breakpoint)> {
10764        let snapshot = self.snapshot(window, cx);
10765        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10766
10767        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10768    }
10769
10770    pub(crate) fn breakpoint_at_anchor(
10771        &self,
10772        breakpoint_position: Anchor,
10773        snapshot: &EditorSnapshot,
10774        cx: &mut Context<Self>,
10775    ) -> Option<(Anchor, Breakpoint)> {
10776        let buffer = self
10777            .buffer
10778            .read(cx)
10779            .buffer_for_anchor(breakpoint_position, cx)?;
10780
10781        let enclosing_excerpt = breakpoint_position.excerpt_id;
10782        let buffer_snapshot = buffer.read(cx).snapshot();
10783
10784        let row = buffer_snapshot
10785            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10786            .row;
10787
10788        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10789        let anchor_end = snapshot
10790            .buffer_snapshot
10791            .anchor_after(Point::new(row, line_len));
10792
10793        self.breakpoint_store
10794            .as_ref()?
10795            .read_with(cx, |breakpoint_store, cx| {
10796                breakpoint_store
10797                    .breakpoints(
10798                        &buffer,
10799                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10800                        &buffer_snapshot,
10801                        cx,
10802                    )
10803                    .next()
10804                    .and_then(|(bp, _)| {
10805                        let breakpoint_row = buffer_snapshot
10806                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10807                            .row;
10808
10809                        if breakpoint_row == row {
10810                            snapshot
10811                                .buffer_snapshot
10812                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10813                                .map(|position| (position, bp.bp.clone()))
10814                        } else {
10815                            None
10816                        }
10817                    })
10818            })
10819    }
10820
10821    pub fn edit_log_breakpoint(
10822        &mut self,
10823        _: &EditLogBreakpoint,
10824        window: &mut Window,
10825        cx: &mut Context<Self>,
10826    ) {
10827        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10828            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10829                message: None,
10830                state: BreakpointState::Enabled,
10831                condition: None,
10832                hit_condition: None,
10833            });
10834
10835            self.add_edit_breakpoint_block(
10836                anchor,
10837                &breakpoint,
10838                BreakpointPromptEditAction::Log,
10839                window,
10840                cx,
10841            );
10842        }
10843    }
10844
10845    fn breakpoints_at_cursors(
10846        &self,
10847        window: &mut Window,
10848        cx: &mut Context<Self>,
10849    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10850        let snapshot = self.snapshot(window, cx);
10851        let cursors = self
10852            .selections
10853            .disjoint_anchors_arc()
10854            .iter()
10855            .map(|selection| {
10856                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10857
10858                let breakpoint_position = self
10859                    .breakpoint_at_row(cursor_position.row, window, cx)
10860                    .map(|bp| bp.0)
10861                    .unwrap_or_else(|| {
10862                        snapshot
10863                            .display_snapshot
10864                            .buffer_snapshot
10865                            .anchor_after(Point::new(cursor_position.row, 0))
10866                    });
10867
10868                let breakpoint = self
10869                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10870                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10871
10872                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10873            })
10874            // 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.
10875            .collect::<HashMap<Anchor, _>>();
10876
10877        cursors.into_iter().collect()
10878    }
10879
10880    pub fn enable_breakpoint(
10881        &mut self,
10882        _: &crate::actions::EnableBreakpoint,
10883        window: &mut Window,
10884        cx: &mut Context<Self>,
10885    ) {
10886        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10887            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10888                continue;
10889            };
10890            self.edit_breakpoint_at_anchor(
10891                anchor,
10892                breakpoint,
10893                BreakpointEditAction::InvertState,
10894                cx,
10895            );
10896        }
10897    }
10898
10899    pub fn disable_breakpoint(
10900        &mut self,
10901        _: &crate::actions::DisableBreakpoint,
10902        window: &mut Window,
10903        cx: &mut Context<Self>,
10904    ) {
10905        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10906            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10907                continue;
10908            };
10909            self.edit_breakpoint_at_anchor(
10910                anchor,
10911                breakpoint,
10912                BreakpointEditAction::InvertState,
10913                cx,
10914            );
10915        }
10916    }
10917
10918    pub fn toggle_breakpoint(
10919        &mut self,
10920        _: &crate::actions::ToggleBreakpoint,
10921        window: &mut Window,
10922        cx: &mut Context<Self>,
10923    ) {
10924        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10925            if let Some(breakpoint) = breakpoint {
10926                self.edit_breakpoint_at_anchor(
10927                    anchor,
10928                    breakpoint,
10929                    BreakpointEditAction::Toggle,
10930                    cx,
10931                );
10932            } else {
10933                self.edit_breakpoint_at_anchor(
10934                    anchor,
10935                    Breakpoint::new_standard(),
10936                    BreakpointEditAction::Toggle,
10937                    cx,
10938                );
10939            }
10940        }
10941    }
10942
10943    pub fn edit_breakpoint_at_anchor(
10944        &mut self,
10945        breakpoint_position: Anchor,
10946        breakpoint: Breakpoint,
10947        edit_action: BreakpointEditAction,
10948        cx: &mut Context<Self>,
10949    ) {
10950        let Some(breakpoint_store) = &self.breakpoint_store else {
10951            return;
10952        };
10953
10954        let Some(buffer) = self
10955            .buffer
10956            .read(cx)
10957            .buffer_for_anchor(breakpoint_position, cx)
10958        else {
10959            return;
10960        };
10961
10962        breakpoint_store.update(cx, |breakpoint_store, cx| {
10963            breakpoint_store.toggle_breakpoint(
10964                buffer,
10965                BreakpointWithPosition {
10966                    position: breakpoint_position.text_anchor,
10967                    bp: breakpoint,
10968                },
10969                edit_action,
10970                cx,
10971            );
10972        });
10973
10974        cx.notify();
10975    }
10976
10977    #[cfg(any(test, feature = "test-support"))]
10978    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10979        self.breakpoint_store.clone()
10980    }
10981
10982    pub fn prepare_restore_change(
10983        &self,
10984        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10985        hunk: &MultiBufferDiffHunk,
10986        cx: &mut App,
10987    ) -> Option<()> {
10988        if hunk.is_created_file() {
10989            return None;
10990        }
10991        let buffer = self.buffer.read(cx);
10992        let diff = buffer.diff_for(hunk.buffer_id)?;
10993        let buffer = buffer.buffer(hunk.buffer_id)?;
10994        let buffer = buffer.read(cx);
10995        let original_text = diff
10996            .read(cx)
10997            .base_text()
10998            .as_rope()
10999            .slice(hunk.diff_base_byte_range.clone());
11000        let buffer_snapshot = buffer.snapshot();
11001        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11002        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11003            probe
11004                .0
11005                .start
11006                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11007                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11008        }) {
11009            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11010            Some(())
11011        } else {
11012            None
11013        }
11014    }
11015
11016    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11017        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11018    }
11019
11020    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11021        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11022    }
11023
11024    fn manipulate_lines<M>(
11025        &mut self,
11026        window: &mut Window,
11027        cx: &mut Context<Self>,
11028        mut manipulate: M,
11029    ) where
11030        M: FnMut(&str) -> LineManipulationResult,
11031    {
11032        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11033
11034        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11035        let buffer = self.buffer.read(cx).snapshot(cx);
11036
11037        let mut edits = Vec::new();
11038
11039        let selections = self.selections.all::<Point>(cx);
11040        let mut selections = selections.iter().peekable();
11041        let mut contiguous_row_selections = Vec::new();
11042        let mut new_selections = Vec::new();
11043        let mut added_lines = 0;
11044        let mut removed_lines = 0;
11045
11046        while let Some(selection) = selections.next() {
11047            let (start_row, end_row) = consume_contiguous_rows(
11048                &mut contiguous_row_selections,
11049                selection,
11050                &display_map,
11051                &mut selections,
11052            );
11053
11054            let start_point = Point::new(start_row.0, 0);
11055            let end_point = Point::new(
11056                end_row.previous_row().0,
11057                buffer.line_len(end_row.previous_row()),
11058            );
11059            let text = buffer
11060                .text_for_range(start_point..end_point)
11061                .collect::<String>();
11062
11063            let LineManipulationResult {
11064                new_text,
11065                line_count_before,
11066                line_count_after,
11067            } = manipulate(&text);
11068
11069            edits.push((start_point..end_point, new_text));
11070
11071            // Selections must change based on added and removed line count
11072            let start_row =
11073                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11074            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11075            new_selections.push(Selection {
11076                id: selection.id,
11077                start: start_row,
11078                end: end_row,
11079                goal: SelectionGoal::None,
11080                reversed: selection.reversed,
11081            });
11082
11083            if line_count_after > line_count_before {
11084                added_lines += line_count_after - line_count_before;
11085            } else if line_count_before > line_count_after {
11086                removed_lines += line_count_before - line_count_after;
11087            }
11088        }
11089
11090        self.transact(window, cx, |this, window, cx| {
11091            let buffer = this.buffer.update(cx, |buffer, cx| {
11092                buffer.edit(edits, None, cx);
11093                buffer.snapshot(cx)
11094            });
11095
11096            // Recalculate offsets on newly edited buffer
11097            let new_selections = new_selections
11098                .iter()
11099                .map(|s| {
11100                    let start_point = Point::new(s.start.0, 0);
11101                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11102                    Selection {
11103                        id: s.id,
11104                        start: buffer.point_to_offset(start_point),
11105                        end: buffer.point_to_offset(end_point),
11106                        goal: s.goal,
11107                        reversed: s.reversed,
11108                    }
11109                })
11110                .collect();
11111
11112            this.change_selections(Default::default(), window, cx, |s| {
11113                s.select(new_selections);
11114            });
11115
11116            this.request_autoscroll(Autoscroll::fit(), cx);
11117        });
11118    }
11119
11120    fn manipulate_immutable_lines<Fn>(
11121        &mut self,
11122        window: &mut Window,
11123        cx: &mut Context<Self>,
11124        mut callback: Fn,
11125    ) where
11126        Fn: FnMut(&mut Vec<&str>),
11127    {
11128        self.manipulate_lines(window, cx, |text| {
11129            let mut lines: Vec<&str> = text.split('\n').collect();
11130            let line_count_before = lines.len();
11131
11132            callback(&mut lines);
11133
11134            LineManipulationResult {
11135                new_text: lines.join("\n"),
11136                line_count_before,
11137                line_count_after: lines.len(),
11138            }
11139        });
11140    }
11141
11142    fn manipulate_mutable_lines<Fn>(
11143        &mut self,
11144        window: &mut Window,
11145        cx: &mut Context<Self>,
11146        mut callback: Fn,
11147    ) where
11148        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11149    {
11150        self.manipulate_lines(window, cx, |text| {
11151            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11152            let line_count_before = lines.len();
11153
11154            callback(&mut lines);
11155
11156            LineManipulationResult {
11157                new_text: lines.join("\n"),
11158                line_count_before,
11159                line_count_after: lines.len(),
11160            }
11161        });
11162    }
11163
11164    pub fn convert_indentation_to_spaces(
11165        &mut self,
11166        _: &ConvertIndentationToSpaces,
11167        window: &mut Window,
11168        cx: &mut Context<Self>,
11169    ) {
11170        let settings = self.buffer.read(cx).language_settings(cx);
11171        let tab_size = settings.tab_size.get() as usize;
11172
11173        self.manipulate_mutable_lines(window, cx, |lines| {
11174            // Allocates a reasonably sized scratch buffer once for the whole loop
11175            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11176            // Avoids recomputing spaces that could be inserted many times
11177            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11178                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11179                .collect();
11180
11181            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11182                let mut chars = line.as_ref().chars();
11183                let mut col = 0;
11184                let mut changed = false;
11185
11186                for ch in chars.by_ref() {
11187                    match ch {
11188                        ' ' => {
11189                            reindented_line.push(' ');
11190                            col += 1;
11191                        }
11192                        '\t' => {
11193                            // \t are converted to spaces depending on the current column
11194                            let spaces_len = tab_size - (col % tab_size);
11195                            reindented_line.extend(&space_cache[spaces_len - 1]);
11196                            col += spaces_len;
11197                            changed = true;
11198                        }
11199                        _ => {
11200                            // If we dont append before break, the character is consumed
11201                            reindented_line.push(ch);
11202                            break;
11203                        }
11204                    }
11205                }
11206
11207                if !changed {
11208                    reindented_line.clear();
11209                    continue;
11210                }
11211                // Append the rest of the line and replace old reference with new one
11212                reindented_line.extend(chars);
11213                *line = Cow::Owned(reindented_line.clone());
11214                reindented_line.clear();
11215            }
11216        });
11217    }
11218
11219    pub fn convert_indentation_to_tabs(
11220        &mut self,
11221        _: &ConvertIndentationToTabs,
11222        window: &mut Window,
11223        cx: &mut Context<Self>,
11224    ) {
11225        let settings = self.buffer.read(cx).language_settings(cx);
11226        let tab_size = settings.tab_size.get() as usize;
11227
11228        self.manipulate_mutable_lines(window, cx, |lines| {
11229            // Allocates a reasonably sized buffer once for the whole loop
11230            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11231            // Avoids recomputing spaces that could be inserted many times
11232            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11233                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11234                .collect();
11235
11236            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11237                let mut chars = line.chars();
11238                let mut spaces_count = 0;
11239                let mut first_non_indent_char = None;
11240                let mut changed = false;
11241
11242                for ch in chars.by_ref() {
11243                    match ch {
11244                        ' ' => {
11245                            // Keep track of spaces. Append \t when we reach tab_size
11246                            spaces_count += 1;
11247                            changed = true;
11248                            if spaces_count == tab_size {
11249                                reindented_line.push('\t');
11250                                spaces_count = 0;
11251                            }
11252                        }
11253                        '\t' => {
11254                            reindented_line.push('\t');
11255                            spaces_count = 0;
11256                        }
11257                        _ => {
11258                            // Dont append it yet, we might have remaining spaces
11259                            first_non_indent_char = Some(ch);
11260                            break;
11261                        }
11262                    }
11263                }
11264
11265                if !changed {
11266                    reindented_line.clear();
11267                    continue;
11268                }
11269                // Remaining spaces that didn't make a full tab stop
11270                if spaces_count > 0 {
11271                    reindented_line.extend(&space_cache[spaces_count - 1]);
11272                }
11273                // If we consume an extra character that was not indentation, add it back
11274                if let Some(extra_char) = first_non_indent_char {
11275                    reindented_line.push(extra_char);
11276                }
11277                // Append the rest of the line and replace old reference with new one
11278                reindented_line.extend(chars);
11279                *line = Cow::Owned(reindented_line.clone());
11280                reindented_line.clear();
11281            }
11282        });
11283    }
11284
11285    pub fn convert_to_upper_case(
11286        &mut self,
11287        _: &ConvertToUpperCase,
11288        window: &mut Window,
11289        cx: &mut Context<Self>,
11290    ) {
11291        self.manipulate_text(window, cx, |text| text.to_uppercase())
11292    }
11293
11294    pub fn convert_to_lower_case(
11295        &mut self,
11296        _: &ConvertToLowerCase,
11297        window: &mut Window,
11298        cx: &mut Context<Self>,
11299    ) {
11300        self.manipulate_text(window, cx, |text| text.to_lowercase())
11301    }
11302
11303    pub fn convert_to_title_case(
11304        &mut self,
11305        _: &ConvertToTitleCase,
11306        window: &mut Window,
11307        cx: &mut Context<Self>,
11308    ) {
11309        self.manipulate_text(window, cx, |text| {
11310            text.split('\n')
11311                .map(|line| line.to_case(Case::Title))
11312                .join("\n")
11313        })
11314    }
11315
11316    pub fn convert_to_snake_case(
11317        &mut self,
11318        _: &ConvertToSnakeCase,
11319        window: &mut Window,
11320        cx: &mut Context<Self>,
11321    ) {
11322        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11323    }
11324
11325    pub fn convert_to_kebab_case(
11326        &mut self,
11327        _: &ConvertToKebabCase,
11328        window: &mut Window,
11329        cx: &mut Context<Self>,
11330    ) {
11331        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11332    }
11333
11334    pub fn convert_to_upper_camel_case(
11335        &mut self,
11336        _: &ConvertToUpperCamelCase,
11337        window: &mut Window,
11338        cx: &mut Context<Self>,
11339    ) {
11340        self.manipulate_text(window, cx, |text| {
11341            text.split('\n')
11342                .map(|line| line.to_case(Case::UpperCamel))
11343                .join("\n")
11344        })
11345    }
11346
11347    pub fn convert_to_lower_camel_case(
11348        &mut self,
11349        _: &ConvertToLowerCamelCase,
11350        window: &mut Window,
11351        cx: &mut Context<Self>,
11352    ) {
11353        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11354    }
11355
11356    pub fn convert_to_opposite_case(
11357        &mut self,
11358        _: &ConvertToOppositeCase,
11359        window: &mut Window,
11360        cx: &mut Context<Self>,
11361    ) {
11362        self.manipulate_text(window, cx, |text| {
11363            text.chars()
11364                .fold(String::with_capacity(text.len()), |mut t, c| {
11365                    if c.is_uppercase() {
11366                        t.extend(c.to_lowercase());
11367                    } else {
11368                        t.extend(c.to_uppercase());
11369                    }
11370                    t
11371                })
11372        })
11373    }
11374
11375    pub fn convert_to_sentence_case(
11376        &mut self,
11377        _: &ConvertToSentenceCase,
11378        window: &mut Window,
11379        cx: &mut Context<Self>,
11380    ) {
11381        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11382    }
11383
11384    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11385        self.manipulate_text(window, cx, |text| {
11386            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11387            if has_upper_case_characters {
11388                text.to_lowercase()
11389            } else {
11390                text.to_uppercase()
11391            }
11392        })
11393    }
11394
11395    pub fn convert_to_rot13(
11396        &mut self,
11397        _: &ConvertToRot13,
11398        window: &mut Window,
11399        cx: &mut Context<Self>,
11400    ) {
11401        self.manipulate_text(window, cx, |text| {
11402            text.chars()
11403                .map(|c| match c {
11404                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11405                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11406                    _ => c,
11407                })
11408                .collect()
11409        })
11410    }
11411
11412    pub fn convert_to_rot47(
11413        &mut self,
11414        _: &ConvertToRot47,
11415        window: &mut Window,
11416        cx: &mut Context<Self>,
11417    ) {
11418        self.manipulate_text(window, cx, |text| {
11419            text.chars()
11420                .map(|c| {
11421                    let code_point = c as u32;
11422                    if code_point >= 33 && code_point <= 126 {
11423                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11424                    }
11425                    c
11426                })
11427                .collect()
11428        })
11429    }
11430
11431    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11432    where
11433        Fn: FnMut(&str) -> String,
11434    {
11435        let buffer = self.buffer.read(cx).snapshot(cx);
11436
11437        let mut new_selections = Vec::new();
11438        let mut edits = Vec::new();
11439        let mut selection_adjustment = 0i32;
11440
11441        for selection in self.selections.all_adjusted(cx) {
11442            let selection_is_empty = selection.is_empty();
11443
11444            let (start, end) = if selection_is_empty {
11445                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11446                (word_range.start, word_range.end)
11447            } else {
11448                (
11449                    buffer.point_to_offset(selection.start),
11450                    buffer.point_to_offset(selection.end),
11451                )
11452            };
11453
11454            let text = buffer.text_for_range(start..end).collect::<String>();
11455            let old_length = text.len() as i32;
11456            let text = callback(&text);
11457
11458            new_selections.push(Selection {
11459                start: (start as i32 - selection_adjustment) as usize,
11460                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11461                goal: SelectionGoal::None,
11462                id: selection.id,
11463                reversed: selection.reversed,
11464            });
11465
11466            selection_adjustment += old_length - text.len() as i32;
11467
11468            edits.push((start..end, text));
11469        }
11470
11471        self.transact(window, cx, |this, window, cx| {
11472            this.buffer.update(cx, |buffer, cx| {
11473                buffer.edit(edits, None, cx);
11474            });
11475
11476            this.change_selections(Default::default(), window, cx, |s| {
11477                s.select(new_selections);
11478            });
11479
11480            this.request_autoscroll(Autoscroll::fit(), cx);
11481        });
11482    }
11483
11484    pub fn move_selection_on_drop(
11485        &mut self,
11486        selection: &Selection<Anchor>,
11487        target: DisplayPoint,
11488        is_cut: bool,
11489        window: &mut Window,
11490        cx: &mut Context<Self>,
11491    ) {
11492        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11493        let buffer = &display_map.buffer_snapshot;
11494        let mut edits = Vec::new();
11495        let insert_point = display_map
11496            .clip_point(target, Bias::Left)
11497            .to_point(&display_map);
11498        let text = buffer
11499            .text_for_range(selection.start..selection.end)
11500            .collect::<String>();
11501        if is_cut {
11502            edits.push(((selection.start..selection.end), String::new()));
11503        }
11504        let insert_anchor = buffer.anchor_before(insert_point);
11505        edits.push(((insert_anchor..insert_anchor), text));
11506        let last_edit_start = insert_anchor.bias_left(buffer);
11507        let last_edit_end = insert_anchor.bias_right(buffer);
11508        self.transact(window, cx, |this, window, cx| {
11509            this.buffer.update(cx, |buffer, cx| {
11510                buffer.edit(edits, None, cx);
11511            });
11512            this.change_selections(Default::default(), window, cx, |s| {
11513                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11514            });
11515        });
11516    }
11517
11518    pub fn clear_selection_drag_state(&mut self) {
11519        self.selection_drag_state = SelectionDragState::None;
11520    }
11521
11522    pub fn duplicate(
11523        &mut self,
11524        upwards: bool,
11525        whole_lines: bool,
11526        window: &mut Window,
11527        cx: &mut Context<Self>,
11528    ) {
11529        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11530
11531        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11532        let buffer = &display_map.buffer_snapshot;
11533        let selections = self.selections.all::<Point>(cx);
11534
11535        let mut edits = Vec::new();
11536        let mut selections_iter = selections.iter().peekable();
11537        while let Some(selection) = selections_iter.next() {
11538            let mut rows = selection.spanned_rows(false, &display_map);
11539            // duplicate line-wise
11540            if whole_lines || selection.start == selection.end {
11541                // Avoid duplicating the same lines twice.
11542                while let Some(next_selection) = selections_iter.peek() {
11543                    let next_rows = next_selection.spanned_rows(false, &display_map);
11544                    if next_rows.start < rows.end {
11545                        rows.end = next_rows.end;
11546                        selections_iter.next().unwrap();
11547                    } else {
11548                        break;
11549                    }
11550                }
11551
11552                // Copy the text from the selected row region and splice it either at the start
11553                // or end of the region.
11554                let start = Point::new(rows.start.0, 0);
11555                let end = Point::new(
11556                    rows.end.previous_row().0,
11557                    buffer.line_len(rows.end.previous_row()),
11558                );
11559                let text = buffer
11560                    .text_for_range(start..end)
11561                    .chain(Some("\n"))
11562                    .collect::<String>();
11563                let insert_location = if upwards {
11564                    Point::new(rows.end.0, 0)
11565                } else {
11566                    start
11567                };
11568                edits.push((insert_location..insert_location, text));
11569            } else {
11570                // duplicate character-wise
11571                let start = selection.start;
11572                let end = selection.end;
11573                let text = buffer.text_for_range(start..end).collect::<String>();
11574                edits.push((selection.end..selection.end, text));
11575            }
11576        }
11577
11578        self.transact(window, cx, |this, _, cx| {
11579            this.buffer.update(cx, |buffer, cx| {
11580                buffer.edit(edits, None, cx);
11581            });
11582
11583            this.request_autoscroll(Autoscroll::fit(), cx);
11584        });
11585    }
11586
11587    pub fn duplicate_line_up(
11588        &mut self,
11589        _: &DuplicateLineUp,
11590        window: &mut Window,
11591        cx: &mut Context<Self>,
11592    ) {
11593        self.duplicate(true, true, window, cx);
11594    }
11595
11596    pub fn duplicate_line_down(
11597        &mut self,
11598        _: &DuplicateLineDown,
11599        window: &mut Window,
11600        cx: &mut Context<Self>,
11601    ) {
11602        self.duplicate(false, true, window, cx);
11603    }
11604
11605    pub fn duplicate_selection(
11606        &mut self,
11607        _: &DuplicateSelection,
11608        window: &mut Window,
11609        cx: &mut Context<Self>,
11610    ) {
11611        self.duplicate(false, false, window, cx);
11612    }
11613
11614    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11615        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11616        if self.mode.is_single_line() {
11617            cx.propagate();
11618            return;
11619        }
11620
11621        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11622        let buffer = self.buffer.read(cx).snapshot(cx);
11623
11624        let mut edits = Vec::new();
11625        let mut unfold_ranges = Vec::new();
11626        let mut refold_creases = Vec::new();
11627
11628        let selections = self.selections.all::<Point>(cx);
11629        let mut selections = selections.iter().peekable();
11630        let mut contiguous_row_selections = Vec::new();
11631        let mut new_selections = Vec::new();
11632
11633        while let Some(selection) = selections.next() {
11634            // Find all the selections that span a contiguous row range
11635            let (start_row, end_row) = consume_contiguous_rows(
11636                &mut contiguous_row_selections,
11637                selection,
11638                &display_map,
11639                &mut selections,
11640            );
11641
11642            // Move the text spanned by the row range to be before the line preceding the row range
11643            if start_row.0 > 0 {
11644                let range_to_move = Point::new(
11645                    start_row.previous_row().0,
11646                    buffer.line_len(start_row.previous_row()),
11647                )
11648                    ..Point::new(
11649                        end_row.previous_row().0,
11650                        buffer.line_len(end_row.previous_row()),
11651                    );
11652                let insertion_point = display_map
11653                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11654                    .0;
11655
11656                // Don't move lines across excerpts
11657                if buffer
11658                    .excerpt_containing(insertion_point..range_to_move.end)
11659                    .is_some()
11660                {
11661                    let text = buffer
11662                        .text_for_range(range_to_move.clone())
11663                        .flat_map(|s| s.chars())
11664                        .skip(1)
11665                        .chain(['\n'])
11666                        .collect::<String>();
11667
11668                    edits.push((
11669                        buffer.anchor_after(range_to_move.start)
11670                            ..buffer.anchor_before(range_to_move.end),
11671                        String::new(),
11672                    ));
11673                    let insertion_anchor = buffer.anchor_after(insertion_point);
11674                    edits.push((insertion_anchor..insertion_anchor, text));
11675
11676                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11677
11678                    // Move selections up
11679                    new_selections.extend(contiguous_row_selections.drain(..).map(
11680                        |mut selection| {
11681                            selection.start.row -= row_delta;
11682                            selection.end.row -= row_delta;
11683                            selection
11684                        },
11685                    ));
11686
11687                    // Move folds up
11688                    unfold_ranges.push(range_to_move.clone());
11689                    for fold in display_map.folds_in_range(
11690                        buffer.anchor_before(range_to_move.start)
11691                            ..buffer.anchor_after(range_to_move.end),
11692                    ) {
11693                        let mut start = fold.range.start.to_point(&buffer);
11694                        let mut end = fold.range.end.to_point(&buffer);
11695                        start.row -= row_delta;
11696                        end.row -= row_delta;
11697                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11698                    }
11699                }
11700            }
11701
11702            // If we didn't move line(s), preserve the existing selections
11703            new_selections.append(&mut contiguous_row_selections);
11704        }
11705
11706        self.transact(window, cx, |this, window, cx| {
11707            this.unfold_ranges(&unfold_ranges, true, true, cx);
11708            this.buffer.update(cx, |buffer, cx| {
11709                for (range, text) in edits {
11710                    buffer.edit([(range, text)], None, cx);
11711                }
11712            });
11713            this.fold_creases(refold_creases, true, window, cx);
11714            this.change_selections(Default::default(), window, cx, |s| {
11715                s.select(new_selections);
11716            })
11717        });
11718    }
11719
11720    pub fn move_line_down(
11721        &mut self,
11722        _: &MoveLineDown,
11723        window: &mut Window,
11724        cx: &mut Context<Self>,
11725    ) {
11726        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11727        if self.mode.is_single_line() {
11728            cx.propagate();
11729            return;
11730        }
11731
11732        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11733        let buffer = self.buffer.read(cx).snapshot(cx);
11734
11735        let mut edits = Vec::new();
11736        let mut unfold_ranges = Vec::new();
11737        let mut refold_creases = Vec::new();
11738
11739        let selections = self.selections.all::<Point>(cx);
11740        let mut selections = selections.iter().peekable();
11741        let mut contiguous_row_selections = Vec::new();
11742        let mut new_selections = Vec::new();
11743
11744        while let Some(selection) = selections.next() {
11745            // Find all the selections that span a contiguous row range
11746            let (start_row, end_row) = consume_contiguous_rows(
11747                &mut contiguous_row_selections,
11748                selection,
11749                &display_map,
11750                &mut selections,
11751            );
11752
11753            // Move the text spanned by the row range to be after the last line of the row range
11754            if end_row.0 <= buffer.max_point().row {
11755                let range_to_move =
11756                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11757                let insertion_point = display_map
11758                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11759                    .0;
11760
11761                // Don't move lines across excerpt boundaries
11762                if buffer
11763                    .excerpt_containing(range_to_move.start..insertion_point)
11764                    .is_some()
11765                {
11766                    let mut text = String::from("\n");
11767                    text.extend(buffer.text_for_range(range_to_move.clone()));
11768                    text.pop(); // Drop trailing newline
11769                    edits.push((
11770                        buffer.anchor_after(range_to_move.start)
11771                            ..buffer.anchor_before(range_to_move.end),
11772                        String::new(),
11773                    ));
11774                    let insertion_anchor = buffer.anchor_after(insertion_point);
11775                    edits.push((insertion_anchor..insertion_anchor, text));
11776
11777                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11778
11779                    // Move selections down
11780                    new_selections.extend(contiguous_row_selections.drain(..).map(
11781                        |mut selection| {
11782                            selection.start.row += row_delta;
11783                            selection.end.row += row_delta;
11784                            selection
11785                        },
11786                    ));
11787
11788                    // Move folds down
11789                    unfold_ranges.push(range_to_move.clone());
11790                    for fold in display_map.folds_in_range(
11791                        buffer.anchor_before(range_to_move.start)
11792                            ..buffer.anchor_after(range_to_move.end),
11793                    ) {
11794                        let mut start = fold.range.start.to_point(&buffer);
11795                        let mut end = fold.range.end.to_point(&buffer);
11796                        start.row += row_delta;
11797                        end.row += row_delta;
11798                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11799                    }
11800                }
11801            }
11802
11803            // If we didn't move line(s), preserve the existing selections
11804            new_selections.append(&mut contiguous_row_selections);
11805        }
11806
11807        self.transact(window, cx, |this, window, cx| {
11808            this.unfold_ranges(&unfold_ranges, true, true, cx);
11809            this.buffer.update(cx, |buffer, cx| {
11810                for (range, text) in edits {
11811                    buffer.edit([(range, text)], None, cx);
11812                }
11813            });
11814            this.fold_creases(refold_creases, true, window, cx);
11815            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11816        });
11817    }
11818
11819    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11820        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11821        let text_layout_details = &self.text_layout_details(window);
11822        self.transact(window, cx, |this, window, cx| {
11823            let edits = this.change_selections(Default::default(), window, cx, |s| {
11824                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11825                s.move_with(|display_map, selection| {
11826                    if !selection.is_empty() {
11827                        return;
11828                    }
11829
11830                    let mut head = selection.head();
11831                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11832                    if head.column() == display_map.line_len(head.row()) {
11833                        transpose_offset = display_map
11834                            .buffer_snapshot
11835                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11836                    }
11837
11838                    if transpose_offset == 0 {
11839                        return;
11840                    }
11841
11842                    *head.column_mut() += 1;
11843                    head = display_map.clip_point(head, Bias::Right);
11844                    let goal = SelectionGoal::HorizontalPosition(
11845                        display_map
11846                            .x_for_display_point(head, text_layout_details)
11847                            .into(),
11848                    );
11849                    selection.collapse_to(head, goal);
11850
11851                    let transpose_start = display_map
11852                        .buffer_snapshot
11853                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11854                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11855                        let transpose_end = display_map
11856                            .buffer_snapshot
11857                            .clip_offset(transpose_offset + 1, Bias::Right);
11858                        if let Some(ch) =
11859                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11860                        {
11861                            edits.push((transpose_start..transpose_offset, String::new()));
11862                            edits.push((transpose_end..transpose_end, ch.to_string()));
11863                        }
11864                    }
11865                });
11866                edits
11867            });
11868            this.buffer
11869                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11870            let selections = this.selections.all::<usize>(cx);
11871            this.change_selections(Default::default(), window, cx, |s| {
11872                s.select(selections);
11873            });
11874        });
11875    }
11876
11877    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11878        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11879        if self.mode.is_single_line() {
11880            cx.propagate();
11881            return;
11882        }
11883
11884        self.rewrap_impl(RewrapOptions::default(), cx)
11885    }
11886
11887    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11888        let buffer = self.buffer.read(cx).snapshot(cx);
11889        let selections = self.selections.all::<Point>(cx);
11890
11891        #[derive(Clone, Debug, PartialEq)]
11892        enum CommentFormat {
11893            /// single line comment, with prefix for line
11894            Line(String),
11895            /// single line within a block comment, with prefix for line
11896            BlockLine(String),
11897            /// a single line of a block comment that includes the initial delimiter
11898            BlockCommentWithStart(BlockCommentConfig),
11899            /// a single line of a block comment that includes the ending delimiter
11900            BlockCommentWithEnd(BlockCommentConfig),
11901        }
11902
11903        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11904        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11905            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11906                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11907                .peekable();
11908
11909            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11910                row
11911            } else {
11912                return Vec::new();
11913            };
11914
11915            let language_settings = buffer.language_settings_at(selection.head(), cx);
11916            let language_scope = buffer.language_scope_at(selection.head());
11917
11918            let indent_and_prefix_for_row =
11919                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11920                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11921                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11922                        &language_scope
11923                    {
11924                        let indent_end = Point::new(row, indent.len);
11925                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11926                        let line_text_after_indent = buffer
11927                            .text_for_range(indent_end..line_end)
11928                            .collect::<String>();
11929
11930                        let is_within_comment_override = buffer
11931                            .language_scope_at(indent_end)
11932                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11933                        let comment_delimiters = if is_within_comment_override {
11934                            // we are within a comment syntax node, but we don't
11935                            // yet know what kind of comment: block, doc or line
11936                            match (
11937                                language_scope.documentation_comment(),
11938                                language_scope.block_comment(),
11939                            ) {
11940                                (Some(config), _) | (_, Some(config))
11941                                    if buffer.contains_str_at(indent_end, &config.start) =>
11942                                {
11943                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11944                                }
11945                                (Some(config), _) | (_, Some(config))
11946                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11947                                {
11948                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11949                                }
11950                                (Some(config), _) | (_, Some(config))
11951                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11952                                {
11953                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11954                                }
11955                                (_, _) => language_scope
11956                                    .line_comment_prefixes()
11957                                    .iter()
11958                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11959                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11960                            }
11961                        } else {
11962                            // we not in an overridden comment node, but we may
11963                            // be within a non-overridden line comment node
11964                            language_scope
11965                                .line_comment_prefixes()
11966                                .iter()
11967                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11968                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11969                        };
11970
11971                        let rewrap_prefix = language_scope
11972                            .rewrap_prefixes()
11973                            .iter()
11974                            .find_map(|prefix_regex| {
11975                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11976                                    if mat.start() == 0 {
11977                                        Some(mat.as_str().to_string())
11978                                    } else {
11979                                        None
11980                                    }
11981                                })
11982                            })
11983                            .flatten();
11984                        (comment_delimiters, rewrap_prefix)
11985                    } else {
11986                        (None, None)
11987                    };
11988                    (indent, comment_prefix, rewrap_prefix)
11989                };
11990
11991            let mut ranges = Vec::new();
11992            let from_empty_selection = selection.is_empty();
11993
11994            let mut current_range_start = first_row;
11995            let mut prev_row = first_row;
11996            let (
11997                mut current_range_indent,
11998                mut current_range_comment_delimiters,
11999                mut current_range_rewrap_prefix,
12000            ) = indent_and_prefix_for_row(first_row);
12001
12002            for row in non_blank_rows_iter.skip(1) {
12003                let has_paragraph_break = row > prev_row + 1;
12004
12005                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12006                    indent_and_prefix_for_row(row);
12007
12008                let has_indent_change = row_indent != current_range_indent;
12009                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12010
12011                let has_boundary_change = has_comment_change
12012                    || row_rewrap_prefix.is_some()
12013                    || (has_indent_change && current_range_comment_delimiters.is_some());
12014
12015                if has_paragraph_break || has_boundary_change {
12016                    ranges.push((
12017                        language_settings.clone(),
12018                        Point::new(current_range_start, 0)
12019                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12020                        current_range_indent,
12021                        current_range_comment_delimiters.clone(),
12022                        current_range_rewrap_prefix.clone(),
12023                        from_empty_selection,
12024                    ));
12025                    current_range_start = row;
12026                    current_range_indent = row_indent;
12027                    current_range_comment_delimiters = row_comment_delimiters;
12028                    current_range_rewrap_prefix = row_rewrap_prefix;
12029                }
12030                prev_row = row;
12031            }
12032
12033            ranges.push((
12034                language_settings.clone(),
12035                Point::new(current_range_start, 0)
12036                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12037                current_range_indent,
12038                current_range_comment_delimiters,
12039                current_range_rewrap_prefix,
12040                from_empty_selection,
12041            ));
12042
12043            ranges
12044        });
12045
12046        let mut edits = Vec::new();
12047        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12048
12049        for (
12050            language_settings,
12051            wrap_range,
12052            mut indent_size,
12053            comment_prefix,
12054            rewrap_prefix,
12055            from_empty_selection,
12056        ) in wrap_ranges
12057        {
12058            let mut start_row = wrap_range.start.row;
12059            let mut end_row = wrap_range.end.row;
12060
12061            // Skip selections that overlap with a range that has already been rewrapped.
12062            let selection_range = start_row..end_row;
12063            if rewrapped_row_ranges
12064                .iter()
12065                .any(|range| range.overlaps(&selection_range))
12066            {
12067                continue;
12068            }
12069
12070            let tab_size = language_settings.tab_size;
12071
12072            let (line_prefix, inside_comment) = match &comment_prefix {
12073                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12074                    (Some(prefix.as_str()), true)
12075                }
12076                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12077                    (Some(prefix.as_ref()), true)
12078                }
12079                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12080                    start: _,
12081                    end: _,
12082                    prefix,
12083                    tab_size,
12084                })) => {
12085                    indent_size.len += tab_size;
12086                    (Some(prefix.as_ref()), true)
12087                }
12088                None => (None, false),
12089            };
12090            let indent_prefix = indent_size.chars().collect::<String>();
12091            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12092
12093            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12094                RewrapBehavior::InComments => inside_comment,
12095                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12096                RewrapBehavior::Anywhere => true,
12097            };
12098
12099            let should_rewrap = options.override_language_settings
12100                || allow_rewrap_based_on_language
12101                || self.hard_wrap.is_some();
12102            if !should_rewrap {
12103                continue;
12104            }
12105
12106            if from_empty_selection {
12107                'expand_upwards: while start_row > 0 {
12108                    let prev_row = start_row - 1;
12109                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12110                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12111                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12112                    {
12113                        start_row = prev_row;
12114                    } else {
12115                        break 'expand_upwards;
12116                    }
12117                }
12118
12119                'expand_downwards: while end_row < buffer.max_point().row {
12120                    let next_row = end_row + 1;
12121                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12122                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12123                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12124                    {
12125                        end_row = next_row;
12126                    } else {
12127                        break 'expand_downwards;
12128                    }
12129                }
12130            }
12131
12132            let start = Point::new(start_row, 0);
12133            let start_offset = start.to_offset(&buffer);
12134            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12135            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12136            let mut first_line_delimiter = None;
12137            let mut last_line_delimiter = None;
12138            let Some(lines_without_prefixes) = selection_text
12139                .lines()
12140                .enumerate()
12141                .map(|(ix, line)| {
12142                    let line_trimmed = line.trim_start();
12143                    if rewrap_prefix.is_some() && ix > 0 {
12144                        Ok(line_trimmed)
12145                    } else if let Some(
12146                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12147                            start,
12148                            prefix,
12149                            end,
12150                            tab_size,
12151                        })
12152                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12153                            start,
12154                            prefix,
12155                            end,
12156                            tab_size,
12157                        }),
12158                    ) = &comment_prefix
12159                    {
12160                        let line_trimmed = line_trimmed
12161                            .strip_prefix(start.as_ref())
12162                            .map(|s| {
12163                                let mut indent_size = indent_size;
12164                                indent_size.len -= tab_size;
12165                                let indent_prefix: String = indent_size.chars().collect();
12166                                first_line_delimiter = Some((indent_prefix, start));
12167                                s.trim_start()
12168                            })
12169                            .unwrap_or(line_trimmed);
12170                        let line_trimmed = line_trimmed
12171                            .strip_suffix(end.as_ref())
12172                            .map(|s| {
12173                                last_line_delimiter = Some(end);
12174                                s.trim_end()
12175                            })
12176                            .unwrap_or(line_trimmed);
12177                        let line_trimmed = line_trimmed
12178                            .strip_prefix(prefix.as_ref())
12179                            .unwrap_or(line_trimmed);
12180                        Ok(line_trimmed)
12181                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12182                        line_trimmed.strip_prefix(prefix).with_context(|| {
12183                            format!("line did not start with prefix {prefix:?}: {line:?}")
12184                        })
12185                    } else {
12186                        line_trimmed
12187                            .strip_prefix(&line_prefix.trim_start())
12188                            .with_context(|| {
12189                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12190                            })
12191                    }
12192                })
12193                .collect::<Result<Vec<_>, _>>()
12194                .log_err()
12195            else {
12196                continue;
12197            };
12198
12199            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12200                buffer
12201                    .language_settings_at(Point::new(start_row, 0), cx)
12202                    .preferred_line_length as usize
12203            });
12204
12205            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12206                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12207            } else {
12208                line_prefix.clone()
12209            };
12210
12211            let wrapped_text = {
12212                let mut wrapped_text = wrap_with_prefix(
12213                    line_prefix,
12214                    subsequent_lines_prefix,
12215                    lines_without_prefixes.join("\n"),
12216                    wrap_column,
12217                    tab_size,
12218                    options.preserve_existing_whitespace,
12219                );
12220
12221                if let Some((indent, delimiter)) = first_line_delimiter {
12222                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12223                }
12224                if let Some(last_line) = last_line_delimiter {
12225                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12226                }
12227
12228                wrapped_text
12229            };
12230
12231            // TODO: should always use char-based diff while still supporting cursor behavior that
12232            // matches vim.
12233            let mut diff_options = DiffOptions::default();
12234            if options.override_language_settings {
12235                diff_options.max_word_diff_len = 0;
12236                diff_options.max_word_diff_line_count = 0;
12237            } else {
12238                diff_options.max_word_diff_len = usize::MAX;
12239                diff_options.max_word_diff_line_count = usize::MAX;
12240            }
12241
12242            for (old_range, new_text) in
12243                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12244            {
12245                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12246                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12247                edits.push((edit_start..edit_end, new_text));
12248            }
12249
12250            rewrapped_row_ranges.push(start_row..=end_row);
12251        }
12252
12253        self.buffer
12254            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12255    }
12256
12257    pub fn cut_common(
12258        &mut self,
12259        cut_no_selection_line: bool,
12260        window: &mut Window,
12261        cx: &mut Context<Self>,
12262    ) -> ClipboardItem {
12263        let mut text = String::new();
12264        let buffer = self.buffer.read(cx).snapshot(cx);
12265        let mut selections = self.selections.all::<Point>(cx);
12266        let mut clipboard_selections = Vec::with_capacity(selections.len());
12267        {
12268            let max_point = buffer.max_point();
12269            let mut is_first = true;
12270            for selection in &mut selections {
12271                let is_entire_line =
12272                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode;
12273                if is_entire_line {
12274                    selection.start = Point::new(selection.start.row, 0);
12275                    if !selection.is_empty() && selection.end.column == 0 {
12276                        selection.end = cmp::min(max_point, selection.end);
12277                    } else {
12278                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12279                    }
12280                    selection.goal = SelectionGoal::None;
12281                }
12282                if is_first {
12283                    is_first = false;
12284                } else {
12285                    text += "\n";
12286                }
12287                let mut len = 0;
12288                for chunk in buffer.text_for_range(selection.start..selection.end) {
12289                    text.push_str(chunk);
12290                    len += chunk.len();
12291                }
12292                clipboard_selections.push(ClipboardSelection {
12293                    len,
12294                    is_entire_line,
12295                    first_line_indent: buffer
12296                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12297                        .len,
12298                });
12299            }
12300        }
12301
12302        self.transact(window, cx, |this, window, cx| {
12303            this.change_selections(Default::default(), window, cx, |s| {
12304                s.select(selections);
12305            });
12306            this.insert("", window, cx);
12307        });
12308        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12309    }
12310
12311    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12312        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12313        let item = self.cut_common(true, window, cx);
12314        cx.write_to_clipboard(item);
12315    }
12316
12317    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12318        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12319        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12320            s.move_with(|snapshot, sel| {
12321                if sel.is_empty() {
12322                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12323                }
12324                if sel.is_empty() {
12325                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12326                }
12327            });
12328        });
12329        let item = self.cut_common(true, window, cx);
12330        cx.set_global(KillRing(item))
12331    }
12332
12333    pub fn kill_ring_yank(
12334        &mut self,
12335        _: &KillRingYank,
12336        window: &mut Window,
12337        cx: &mut Context<Self>,
12338    ) {
12339        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12340        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12341            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12342                (kill_ring.text().to_string(), kill_ring.metadata_json())
12343            } else {
12344                return;
12345            }
12346        } else {
12347            return;
12348        };
12349        self.do_paste(&text, metadata, false, window, cx);
12350    }
12351
12352    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12353        self.do_copy(true, cx);
12354    }
12355
12356    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12357        self.do_copy(false, cx);
12358    }
12359
12360    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12361        let selections = self.selections.all::<Point>(cx);
12362        let buffer = self.buffer.read(cx).read(cx);
12363        let mut text = String::new();
12364
12365        let mut clipboard_selections = Vec::with_capacity(selections.len());
12366        {
12367            let max_point = buffer.max_point();
12368            let mut is_first = true;
12369            for selection in &selections {
12370                let mut start = selection.start;
12371                let mut end = selection.end;
12372                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12373                if is_entire_line {
12374                    start = Point::new(start.row, 0);
12375                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12376                }
12377
12378                let mut trimmed_selections = Vec::new();
12379                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12380                    let row = MultiBufferRow(start.row);
12381                    let first_indent = buffer.indent_size_for_line(row);
12382                    if first_indent.len == 0 || start.column > first_indent.len {
12383                        trimmed_selections.push(start..end);
12384                    } else {
12385                        trimmed_selections.push(
12386                            Point::new(row.0, first_indent.len)
12387                                ..Point::new(row.0, buffer.line_len(row)),
12388                        );
12389                        for row in start.row + 1..=end.row {
12390                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12391                            if row == end.row {
12392                                line_len = end.column;
12393                            }
12394                            if line_len == 0 {
12395                                trimmed_selections
12396                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12397                                continue;
12398                            }
12399                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12400                            if row_indent_size.len >= first_indent.len {
12401                                trimmed_selections.push(
12402                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12403                                );
12404                            } else {
12405                                trimmed_selections.clear();
12406                                trimmed_selections.push(start..end);
12407                                break;
12408                            }
12409                        }
12410                    }
12411                } else {
12412                    trimmed_selections.push(start..end);
12413                }
12414
12415                for trimmed_range in trimmed_selections {
12416                    if is_first {
12417                        is_first = false;
12418                    } else {
12419                        text += "\n";
12420                    }
12421                    let mut len = 0;
12422                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12423                        text.push_str(chunk);
12424                        len += chunk.len();
12425                    }
12426                    clipboard_selections.push(ClipboardSelection {
12427                        len,
12428                        is_entire_line,
12429                        first_line_indent: buffer
12430                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12431                            .len,
12432                    });
12433                }
12434            }
12435        }
12436
12437        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12438            text,
12439            clipboard_selections,
12440        ));
12441    }
12442
12443    pub fn do_paste(
12444        &mut self,
12445        text: &String,
12446        clipboard_selections: Option<Vec<ClipboardSelection>>,
12447        handle_entire_lines: bool,
12448        window: &mut Window,
12449        cx: &mut Context<Self>,
12450    ) {
12451        if self.read_only(cx) {
12452            return;
12453        }
12454
12455        let clipboard_text = Cow::Borrowed(text.as_str());
12456
12457        self.transact(window, cx, |this, window, cx| {
12458            let had_active_edit_prediction = this.has_active_edit_prediction();
12459            let old_selections = this.selections.all::<usize>(cx);
12460            let cursor_offset = this.selections.last::<usize>(cx).head();
12461
12462            if let Some(mut clipboard_selections) = clipboard_selections {
12463                let all_selections_were_entire_line =
12464                    clipboard_selections.iter().all(|s| s.is_entire_line);
12465                let first_selection_indent_column =
12466                    clipboard_selections.first().map(|s| s.first_line_indent);
12467                if clipboard_selections.len() != old_selections.len() {
12468                    clipboard_selections.drain(..);
12469                }
12470                let mut auto_indent_on_paste = true;
12471
12472                this.buffer.update(cx, |buffer, cx| {
12473                    let snapshot = buffer.read(cx);
12474                    auto_indent_on_paste = snapshot
12475                        .language_settings_at(cursor_offset, cx)
12476                        .auto_indent_on_paste;
12477
12478                    let mut start_offset = 0;
12479                    let mut edits = Vec::new();
12480                    let mut original_indent_columns = Vec::new();
12481                    for (ix, selection) in old_selections.iter().enumerate() {
12482                        let to_insert;
12483                        let entire_line;
12484                        let original_indent_column;
12485                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12486                            let end_offset = start_offset + clipboard_selection.len;
12487                            to_insert = &clipboard_text[start_offset..end_offset];
12488                            entire_line = clipboard_selection.is_entire_line;
12489                            start_offset = end_offset + 1;
12490                            original_indent_column = Some(clipboard_selection.first_line_indent);
12491                        } else {
12492                            to_insert = &*clipboard_text;
12493                            entire_line = all_selections_were_entire_line;
12494                            original_indent_column = first_selection_indent_column
12495                        }
12496
12497                        let (range, to_insert) =
12498                            if selection.is_empty() && handle_entire_lines && entire_line {
12499                                // If the corresponding selection was empty when this slice of the
12500                                // clipboard text was written, then the entire line containing the
12501                                // selection was copied. If this selection is also currently empty,
12502                                // then paste the line before the current line of the buffer.
12503                                let column = selection.start.to_point(&snapshot).column as usize;
12504                                let line_start = selection.start - column;
12505                                (line_start..line_start, Cow::Borrowed(to_insert))
12506                            } else {
12507                                let language = snapshot.language_at(selection.head());
12508                                let range = selection.range();
12509                                if let Some(language) = language
12510                                    && language.name() == "Markdown".into()
12511                                {
12512                                    edit_for_markdown_paste(
12513                                        &snapshot,
12514                                        range,
12515                                        to_insert,
12516                                        url::Url::parse(to_insert).ok(),
12517                                    )
12518                                } else {
12519                                    (range, Cow::Borrowed(to_insert))
12520                                }
12521                            };
12522
12523                        edits.push((range, to_insert));
12524                        original_indent_columns.push(original_indent_column);
12525                    }
12526                    drop(snapshot);
12527
12528                    buffer.edit(
12529                        edits,
12530                        if auto_indent_on_paste {
12531                            Some(AutoindentMode::Block {
12532                                original_indent_columns,
12533                            })
12534                        } else {
12535                            None
12536                        },
12537                        cx,
12538                    );
12539                });
12540
12541                let selections = this.selections.all::<usize>(cx);
12542                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12543            } else {
12544                let url = url::Url::parse(&clipboard_text).ok();
12545
12546                let auto_indent_mode = if !clipboard_text.is_empty() {
12547                    Some(AutoindentMode::Block {
12548                        original_indent_columns: Vec::new(),
12549                    })
12550                } else {
12551                    None
12552                };
12553
12554                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12555                    let snapshot = buffer.snapshot(cx);
12556
12557                    let anchors = old_selections
12558                        .iter()
12559                        .map(|s| {
12560                            let anchor = snapshot.anchor_after(s.head());
12561                            s.map(|_| anchor)
12562                        })
12563                        .collect::<Vec<_>>();
12564
12565                    let mut edits = Vec::new();
12566
12567                    for selection in old_selections.iter() {
12568                        let language = snapshot.language_at(selection.head());
12569                        let range = selection.range();
12570
12571                        let (edit_range, edit_text) = if let Some(language) = language
12572                            && language.name() == "Markdown".into()
12573                        {
12574                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12575                        } else {
12576                            (range, clipboard_text.clone())
12577                        };
12578
12579                        edits.push((edit_range, edit_text));
12580                    }
12581
12582                    drop(snapshot);
12583                    buffer.edit(edits, auto_indent_mode, cx);
12584
12585                    anchors
12586                });
12587
12588                this.change_selections(Default::default(), window, cx, |s| {
12589                    s.select_anchors(selection_anchors);
12590                });
12591            }
12592
12593            let trigger_in_words =
12594                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12595
12596            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12597        });
12598    }
12599
12600    pub fn diff_clipboard_with_selection(
12601        &mut self,
12602        _: &DiffClipboardWithSelection,
12603        window: &mut Window,
12604        cx: &mut Context<Self>,
12605    ) {
12606        let selections = self.selections.all::<usize>(cx);
12607
12608        if selections.is_empty() {
12609            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12610            return;
12611        };
12612
12613        let clipboard_text = match cx.read_from_clipboard() {
12614            Some(item) => match item.entries().first() {
12615                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12616                _ => None,
12617            },
12618            None => None,
12619        };
12620
12621        let Some(clipboard_text) = clipboard_text else {
12622            log::warn!("Clipboard doesn't contain text.");
12623            return;
12624        };
12625
12626        window.dispatch_action(
12627            Box::new(DiffClipboardWithSelectionData {
12628                clipboard_text,
12629                editor: cx.entity(),
12630            }),
12631            cx,
12632        );
12633    }
12634
12635    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12636        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12637        if let Some(item) = cx.read_from_clipboard() {
12638            let entries = item.entries();
12639
12640            match entries.first() {
12641                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12642                // of all the pasted entries.
12643                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12644                    .do_paste(
12645                        clipboard_string.text(),
12646                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12647                        true,
12648                        window,
12649                        cx,
12650                    ),
12651                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12652            }
12653        }
12654    }
12655
12656    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12657        if self.read_only(cx) {
12658            return;
12659        }
12660
12661        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12662
12663        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12664            if let Some((selections, _)) =
12665                self.selection_history.transaction(transaction_id).cloned()
12666            {
12667                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12668                    s.select_anchors(selections.to_vec());
12669                });
12670            } else {
12671                log::error!(
12672                    "No entry in selection_history found for undo. \
12673                     This may correspond to a bug where undo does not update the selection. \
12674                     If this is occurring, please add details to \
12675                     https://github.com/zed-industries/zed/issues/22692"
12676                );
12677            }
12678            self.request_autoscroll(Autoscroll::fit(), cx);
12679            self.unmark_text(window, cx);
12680            self.refresh_edit_prediction(true, false, window, cx);
12681            cx.emit(EditorEvent::Edited { transaction_id });
12682            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12683        }
12684    }
12685
12686    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12687        if self.read_only(cx) {
12688            return;
12689        }
12690
12691        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12692
12693        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12694            if let Some((_, Some(selections))) =
12695                self.selection_history.transaction(transaction_id).cloned()
12696            {
12697                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12698                    s.select_anchors(selections.to_vec());
12699                });
12700            } else {
12701                log::error!(
12702                    "No entry in selection_history found for redo. \
12703                     This may correspond to a bug where undo does not update the selection. \
12704                     If this is occurring, please add details to \
12705                     https://github.com/zed-industries/zed/issues/22692"
12706                );
12707            }
12708            self.request_autoscroll(Autoscroll::fit(), cx);
12709            self.unmark_text(window, cx);
12710            self.refresh_edit_prediction(true, false, window, cx);
12711            cx.emit(EditorEvent::Edited { transaction_id });
12712        }
12713    }
12714
12715    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12716        self.buffer
12717            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12718    }
12719
12720    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12721        self.buffer
12722            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12723    }
12724
12725    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12726        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12727        self.change_selections(Default::default(), window, cx, |s| {
12728            s.move_with(|map, selection| {
12729                let cursor = if selection.is_empty() {
12730                    movement::left(map, selection.start)
12731                } else {
12732                    selection.start
12733                };
12734                selection.collapse_to(cursor, SelectionGoal::None);
12735            });
12736        })
12737    }
12738
12739    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12740        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12741        self.change_selections(Default::default(), window, cx, |s| {
12742            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12743        })
12744    }
12745
12746    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12747        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12748        self.change_selections(Default::default(), window, cx, |s| {
12749            s.move_with(|map, selection| {
12750                let cursor = if selection.is_empty() {
12751                    movement::right(map, selection.end)
12752                } else {
12753                    selection.end
12754                };
12755                selection.collapse_to(cursor, SelectionGoal::None)
12756            });
12757        })
12758    }
12759
12760    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12761        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12762        self.change_selections(Default::default(), window, cx, |s| {
12763            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12764        })
12765    }
12766
12767    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12768        if self.take_rename(true, window, cx).is_some() {
12769            return;
12770        }
12771
12772        if self.mode.is_single_line() {
12773            cx.propagate();
12774            return;
12775        }
12776
12777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12778
12779        let text_layout_details = &self.text_layout_details(window);
12780        let selection_count = self.selections.count();
12781        let first_selection = self.selections.first_anchor();
12782
12783        self.change_selections(Default::default(), window, cx, |s| {
12784            s.move_with(|map, selection| {
12785                if !selection.is_empty() {
12786                    selection.goal = SelectionGoal::None;
12787                }
12788                let (cursor, goal) = movement::up(
12789                    map,
12790                    selection.start,
12791                    selection.goal,
12792                    false,
12793                    text_layout_details,
12794                );
12795                selection.collapse_to(cursor, goal);
12796            });
12797        });
12798
12799        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12800        {
12801            cx.propagate();
12802        }
12803    }
12804
12805    pub fn move_up_by_lines(
12806        &mut self,
12807        action: &MoveUpByLines,
12808        window: &mut Window,
12809        cx: &mut Context<Self>,
12810    ) {
12811        if self.take_rename(true, window, cx).is_some() {
12812            return;
12813        }
12814
12815        if self.mode.is_single_line() {
12816            cx.propagate();
12817            return;
12818        }
12819
12820        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12821
12822        let text_layout_details = &self.text_layout_details(window);
12823
12824        self.change_selections(Default::default(), window, cx, |s| {
12825            s.move_with(|map, selection| {
12826                if !selection.is_empty() {
12827                    selection.goal = SelectionGoal::None;
12828                }
12829                let (cursor, goal) = movement::up_by_rows(
12830                    map,
12831                    selection.start,
12832                    action.lines,
12833                    selection.goal,
12834                    false,
12835                    text_layout_details,
12836                );
12837                selection.collapse_to(cursor, goal);
12838            });
12839        })
12840    }
12841
12842    pub fn move_down_by_lines(
12843        &mut self,
12844        action: &MoveDownByLines,
12845        window: &mut Window,
12846        cx: &mut Context<Self>,
12847    ) {
12848        if self.take_rename(true, window, cx).is_some() {
12849            return;
12850        }
12851
12852        if self.mode.is_single_line() {
12853            cx.propagate();
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_with(|map, selection| {
12863                if !selection.is_empty() {
12864                    selection.goal = SelectionGoal::None;
12865                }
12866                let (cursor, goal) = movement::down_by_rows(
12867                    map,
12868                    selection.start,
12869                    action.lines,
12870                    selection.goal,
12871                    false,
12872                    text_layout_details,
12873                );
12874                selection.collapse_to(cursor, goal);
12875            });
12876        })
12877    }
12878
12879    pub fn select_down_by_lines(
12880        &mut self,
12881        action: &SelectDownByLines,
12882        window: &mut Window,
12883        cx: &mut Context<Self>,
12884    ) {
12885        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12886        let text_layout_details = &self.text_layout_details(window);
12887        self.change_selections(Default::default(), window, cx, |s| {
12888            s.move_heads_with(|map, head, goal| {
12889                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12890            })
12891        })
12892    }
12893
12894    pub fn select_up_by_lines(
12895        &mut self,
12896        action: &SelectUpByLines,
12897        window: &mut Window,
12898        cx: &mut Context<Self>,
12899    ) {
12900        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12901        let text_layout_details = &self.text_layout_details(window);
12902        self.change_selections(Default::default(), window, cx, |s| {
12903            s.move_heads_with(|map, head, goal| {
12904                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12905            })
12906        })
12907    }
12908
12909    pub fn select_page_up(
12910        &mut self,
12911        _: &SelectPageUp,
12912        window: &mut Window,
12913        cx: &mut Context<Self>,
12914    ) {
12915        let Some(row_count) = self.visible_row_count() else {
12916            return;
12917        };
12918
12919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12920
12921        let text_layout_details = &self.text_layout_details(window);
12922
12923        self.change_selections(Default::default(), window, cx, |s| {
12924            s.move_heads_with(|map, head, goal| {
12925                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12926            })
12927        })
12928    }
12929
12930    pub fn move_page_up(
12931        &mut self,
12932        action: &MovePageUp,
12933        window: &mut Window,
12934        cx: &mut Context<Self>,
12935    ) {
12936        if self.take_rename(true, window, cx).is_some() {
12937            return;
12938        }
12939
12940        if self
12941            .context_menu
12942            .borrow_mut()
12943            .as_mut()
12944            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12945            .unwrap_or(false)
12946        {
12947            return;
12948        }
12949
12950        if matches!(self.mode, EditorMode::SingleLine) {
12951            cx.propagate();
12952            return;
12953        }
12954
12955        let Some(row_count) = self.visible_row_count() else {
12956            return;
12957        };
12958
12959        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12960
12961        let effects = if action.center_cursor {
12962            SelectionEffects::scroll(Autoscroll::center())
12963        } else {
12964            SelectionEffects::default()
12965        };
12966
12967        let text_layout_details = &self.text_layout_details(window);
12968
12969        self.change_selections(effects, window, cx, |s| {
12970            s.move_with(|map, selection| {
12971                if !selection.is_empty() {
12972                    selection.goal = SelectionGoal::None;
12973                }
12974                let (cursor, goal) = movement::up_by_rows(
12975                    map,
12976                    selection.end,
12977                    row_count,
12978                    selection.goal,
12979                    false,
12980                    text_layout_details,
12981                );
12982                selection.collapse_to(cursor, goal);
12983            });
12984        });
12985    }
12986
12987    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12988        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12989        let text_layout_details = &self.text_layout_details(window);
12990        self.change_selections(Default::default(), window, cx, |s| {
12991            s.move_heads_with(|map, head, goal| {
12992                movement::up(map, head, goal, false, text_layout_details)
12993            })
12994        })
12995    }
12996
12997    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12998        self.take_rename(true, window, cx);
12999
13000        if self.mode.is_single_line() {
13001            cx.propagate();
13002            return;
13003        }
13004
13005        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13006
13007        let text_layout_details = &self.text_layout_details(window);
13008        let selection_count = self.selections.count();
13009        let first_selection = self.selections.first_anchor();
13010
13011        self.change_selections(Default::default(), window, cx, |s| {
13012            s.move_with(|map, selection| {
13013                if !selection.is_empty() {
13014                    selection.goal = SelectionGoal::None;
13015                }
13016                let (cursor, goal) = movement::down(
13017                    map,
13018                    selection.end,
13019                    selection.goal,
13020                    false,
13021                    text_layout_details,
13022                );
13023                selection.collapse_to(cursor, goal);
13024            });
13025        });
13026
13027        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13028        {
13029            cx.propagate();
13030        }
13031    }
13032
13033    pub fn select_page_down(
13034        &mut self,
13035        _: &SelectPageDown,
13036        window: &mut Window,
13037        cx: &mut Context<Self>,
13038    ) {
13039        let Some(row_count) = self.visible_row_count() else {
13040            return;
13041        };
13042
13043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13044
13045        let text_layout_details = &self.text_layout_details(window);
13046
13047        self.change_selections(Default::default(), window, cx, |s| {
13048            s.move_heads_with(|map, head, goal| {
13049                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13050            })
13051        })
13052    }
13053
13054    pub fn move_page_down(
13055        &mut self,
13056        action: &MovePageDown,
13057        window: &mut Window,
13058        cx: &mut Context<Self>,
13059    ) {
13060        if self.take_rename(true, window, cx).is_some() {
13061            return;
13062        }
13063
13064        if self
13065            .context_menu
13066            .borrow_mut()
13067            .as_mut()
13068            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13069            .unwrap_or(false)
13070        {
13071            return;
13072        }
13073
13074        if matches!(self.mode, EditorMode::SingleLine) {
13075            cx.propagate();
13076            return;
13077        }
13078
13079        let Some(row_count) = self.visible_row_count() else {
13080            return;
13081        };
13082
13083        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13084
13085        let effects = if action.center_cursor {
13086            SelectionEffects::scroll(Autoscroll::center())
13087        } else {
13088            SelectionEffects::default()
13089        };
13090
13091        let text_layout_details = &self.text_layout_details(window);
13092        self.change_selections(effects, window, cx, |s| {
13093            s.move_with(|map, selection| {
13094                if !selection.is_empty() {
13095                    selection.goal = SelectionGoal::None;
13096                }
13097                let (cursor, goal) = movement::down_by_rows(
13098                    map,
13099                    selection.end,
13100                    row_count,
13101                    selection.goal,
13102                    false,
13103                    text_layout_details,
13104                );
13105                selection.collapse_to(cursor, goal);
13106            });
13107        });
13108    }
13109
13110    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13112        let text_layout_details = &self.text_layout_details(window);
13113        self.change_selections(Default::default(), window, cx, |s| {
13114            s.move_heads_with(|map, head, goal| {
13115                movement::down(map, head, goal, false, text_layout_details)
13116            })
13117        });
13118    }
13119
13120    pub fn context_menu_first(
13121        &mut self,
13122        _: &ContextMenuFirst,
13123        window: &mut Window,
13124        cx: &mut Context<Self>,
13125    ) {
13126        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13127            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13128        }
13129    }
13130
13131    pub fn context_menu_prev(
13132        &mut self,
13133        _: &ContextMenuPrevious,
13134        window: &mut Window,
13135        cx: &mut Context<Self>,
13136    ) {
13137        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13138            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13139        }
13140    }
13141
13142    pub fn context_menu_next(
13143        &mut self,
13144        _: &ContextMenuNext,
13145        window: &mut Window,
13146        cx: &mut Context<Self>,
13147    ) {
13148        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13149            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13150        }
13151    }
13152
13153    pub fn context_menu_last(
13154        &mut self,
13155        _: &ContextMenuLast,
13156        window: &mut Window,
13157        cx: &mut Context<Self>,
13158    ) {
13159        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13160            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13161        }
13162    }
13163
13164    pub fn signature_help_prev(
13165        &mut self,
13166        _: &SignatureHelpPrevious,
13167        _: &mut Window,
13168        cx: &mut Context<Self>,
13169    ) {
13170        if let Some(popover) = self.signature_help_state.popover_mut() {
13171            if popover.current_signature == 0 {
13172                popover.current_signature = popover.signatures.len() - 1;
13173            } else {
13174                popover.current_signature -= 1;
13175            }
13176            cx.notify();
13177        }
13178    }
13179
13180    pub fn signature_help_next(
13181        &mut self,
13182        _: &SignatureHelpNext,
13183        _: &mut Window,
13184        cx: &mut Context<Self>,
13185    ) {
13186        if let Some(popover) = self.signature_help_state.popover_mut() {
13187            if popover.current_signature + 1 == popover.signatures.len() {
13188                popover.current_signature = 0;
13189            } else {
13190                popover.current_signature += 1;
13191            }
13192            cx.notify();
13193        }
13194    }
13195
13196    pub fn move_to_previous_word_start(
13197        &mut self,
13198        _: &MoveToPreviousWordStart,
13199        window: &mut Window,
13200        cx: &mut Context<Self>,
13201    ) {
13202        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13203        self.change_selections(Default::default(), window, cx, |s| {
13204            s.move_cursors_with(|map, head, _| {
13205                (
13206                    movement::previous_word_start(map, head),
13207                    SelectionGoal::None,
13208                )
13209            });
13210        })
13211    }
13212
13213    pub fn move_to_previous_subword_start(
13214        &mut self,
13215        _: &MoveToPreviousSubwordStart,
13216        window: &mut Window,
13217        cx: &mut Context<Self>,
13218    ) {
13219        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13220        self.change_selections(Default::default(), window, cx, |s| {
13221            s.move_cursors_with(|map, head, _| {
13222                (
13223                    movement::previous_subword_start(map, head),
13224                    SelectionGoal::None,
13225                )
13226            });
13227        })
13228    }
13229
13230    pub fn select_to_previous_word_start(
13231        &mut self,
13232        _: &SelectToPreviousWordStart,
13233        window: &mut Window,
13234        cx: &mut Context<Self>,
13235    ) {
13236        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13237        self.change_selections(Default::default(), window, cx, |s| {
13238            s.move_heads_with(|map, head, _| {
13239                (
13240                    movement::previous_word_start(map, head),
13241                    SelectionGoal::None,
13242                )
13243            });
13244        })
13245    }
13246
13247    pub fn select_to_previous_subword_start(
13248        &mut self,
13249        _: &SelectToPreviousSubwordStart,
13250        window: &mut Window,
13251        cx: &mut Context<Self>,
13252    ) {
13253        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13254        self.change_selections(Default::default(), window, cx, |s| {
13255            s.move_heads_with(|map, head, _| {
13256                (
13257                    movement::previous_subword_start(map, head),
13258                    SelectionGoal::None,
13259                )
13260            });
13261        })
13262    }
13263
13264    pub fn delete_to_previous_word_start(
13265        &mut self,
13266        action: &DeleteToPreviousWordStart,
13267        window: &mut Window,
13268        cx: &mut Context<Self>,
13269    ) {
13270        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13271        self.transact(window, cx, |this, window, cx| {
13272            this.select_autoclose_pair(window, cx);
13273            this.change_selections(Default::default(), window, cx, |s| {
13274                s.move_with(|map, selection| {
13275                    if selection.is_empty() {
13276                        let mut cursor = if action.ignore_newlines {
13277                            movement::previous_word_start(map, selection.head())
13278                        } else {
13279                            movement::previous_word_start_or_newline(map, selection.head())
13280                        };
13281                        cursor = movement::adjust_greedy_deletion(
13282                            map,
13283                            selection.head(),
13284                            cursor,
13285                            action.ignore_brackets,
13286                        );
13287                        selection.set_head(cursor, SelectionGoal::None);
13288                    }
13289                });
13290            });
13291            this.insert("", window, cx);
13292        });
13293    }
13294
13295    pub fn delete_to_previous_subword_start(
13296        &mut self,
13297        _: &DeleteToPreviousSubwordStart,
13298        window: &mut Window,
13299        cx: &mut Context<Self>,
13300    ) {
13301        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13302        self.transact(window, cx, |this, window, cx| {
13303            this.select_autoclose_pair(window, cx);
13304            this.change_selections(Default::default(), window, cx, |s| {
13305                s.move_with(|map, selection| {
13306                    if selection.is_empty() {
13307                        let mut cursor = movement::previous_subword_start(map, selection.head());
13308                        cursor =
13309                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13310                        selection.set_head(cursor, SelectionGoal::None);
13311                    }
13312                });
13313            });
13314            this.insert("", window, cx);
13315        });
13316    }
13317
13318    pub fn move_to_next_word_end(
13319        &mut self,
13320        _: &MoveToNextWordEnd,
13321        window: &mut Window,
13322        cx: &mut Context<Self>,
13323    ) {
13324        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13325        self.change_selections(Default::default(), window, cx, |s| {
13326            s.move_cursors_with(|map, head, _| {
13327                (movement::next_word_end(map, head), SelectionGoal::None)
13328            });
13329        })
13330    }
13331
13332    pub fn move_to_next_subword_end(
13333        &mut self,
13334        _: &MoveToNextSubwordEnd,
13335        window: &mut Window,
13336        cx: &mut Context<Self>,
13337    ) {
13338        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13339        self.change_selections(Default::default(), window, cx, |s| {
13340            s.move_cursors_with(|map, head, _| {
13341                (movement::next_subword_end(map, head), SelectionGoal::None)
13342            });
13343        })
13344    }
13345
13346    pub fn select_to_next_word_end(
13347        &mut self,
13348        _: &SelectToNextWordEnd,
13349        window: &mut Window,
13350        cx: &mut Context<Self>,
13351    ) {
13352        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13353        self.change_selections(Default::default(), window, cx, |s| {
13354            s.move_heads_with(|map, head, _| {
13355                (movement::next_word_end(map, head), SelectionGoal::None)
13356            });
13357        })
13358    }
13359
13360    pub fn select_to_next_subword_end(
13361        &mut self,
13362        _: &SelectToNextSubwordEnd,
13363        window: &mut Window,
13364        cx: &mut Context<Self>,
13365    ) {
13366        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13367        self.change_selections(Default::default(), window, cx, |s| {
13368            s.move_heads_with(|map, head, _| {
13369                (movement::next_subword_end(map, head), SelectionGoal::None)
13370            });
13371        })
13372    }
13373
13374    pub fn delete_to_next_word_end(
13375        &mut self,
13376        action: &DeleteToNextWordEnd,
13377        window: &mut Window,
13378        cx: &mut Context<Self>,
13379    ) {
13380        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13381        self.transact(window, cx, |this, window, cx| {
13382            this.change_selections(Default::default(), window, cx, |s| {
13383                s.move_with(|map, selection| {
13384                    if selection.is_empty() {
13385                        let mut cursor = if action.ignore_newlines {
13386                            movement::next_word_end(map, selection.head())
13387                        } else {
13388                            movement::next_word_end_or_newline(map, selection.head())
13389                        };
13390                        cursor = movement::adjust_greedy_deletion(
13391                            map,
13392                            selection.head(),
13393                            cursor,
13394                            action.ignore_brackets,
13395                        );
13396                        selection.set_head(cursor, SelectionGoal::None);
13397                    }
13398                });
13399            });
13400            this.insert("", window, cx);
13401        });
13402    }
13403
13404    pub fn delete_to_next_subword_end(
13405        &mut self,
13406        _: &DeleteToNextSubwordEnd,
13407        window: &mut Window,
13408        cx: &mut Context<Self>,
13409    ) {
13410        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13411        self.transact(window, cx, |this, window, cx| {
13412            this.change_selections(Default::default(), window, cx, |s| {
13413                s.move_with(|map, selection| {
13414                    if selection.is_empty() {
13415                        let mut cursor = movement::next_subword_end(map, selection.head());
13416                        cursor =
13417                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13418                        selection.set_head(cursor, SelectionGoal::None);
13419                    }
13420                });
13421            });
13422            this.insert("", window, cx);
13423        });
13424    }
13425
13426    pub fn move_to_beginning_of_line(
13427        &mut self,
13428        action: &MoveToBeginningOfLine,
13429        window: &mut Window,
13430        cx: &mut Context<Self>,
13431    ) {
13432        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13433        self.change_selections(Default::default(), window, cx, |s| {
13434            s.move_cursors_with(|map, head, _| {
13435                (
13436                    movement::indented_line_beginning(
13437                        map,
13438                        head,
13439                        action.stop_at_soft_wraps,
13440                        action.stop_at_indent,
13441                    ),
13442                    SelectionGoal::None,
13443                )
13444            });
13445        })
13446    }
13447
13448    pub fn select_to_beginning_of_line(
13449        &mut self,
13450        action: &SelectToBeginningOfLine,
13451        window: &mut Window,
13452        cx: &mut Context<Self>,
13453    ) {
13454        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13455        self.change_selections(Default::default(), window, cx, |s| {
13456            s.move_heads_with(|map, head, _| {
13457                (
13458                    movement::indented_line_beginning(
13459                        map,
13460                        head,
13461                        action.stop_at_soft_wraps,
13462                        action.stop_at_indent,
13463                    ),
13464                    SelectionGoal::None,
13465                )
13466            });
13467        });
13468    }
13469
13470    pub fn delete_to_beginning_of_line(
13471        &mut self,
13472        action: &DeleteToBeginningOfLine,
13473        window: &mut Window,
13474        cx: &mut Context<Self>,
13475    ) {
13476        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13477        self.transact(window, cx, |this, window, cx| {
13478            this.change_selections(Default::default(), window, cx, |s| {
13479                s.move_with(|_, selection| {
13480                    selection.reversed = true;
13481                });
13482            });
13483
13484            this.select_to_beginning_of_line(
13485                &SelectToBeginningOfLine {
13486                    stop_at_soft_wraps: false,
13487                    stop_at_indent: action.stop_at_indent,
13488                },
13489                window,
13490                cx,
13491            );
13492            this.backspace(&Backspace, window, cx);
13493        });
13494    }
13495
13496    pub fn move_to_end_of_line(
13497        &mut self,
13498        action: &MoveToEndOfLine,
13499        window: &mut Window,
13500        cx: &mut Context<Self>,
13501    ) {
13502        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13503        self.change_selections(Default::default(), window, cx, |s| {
13504            s.move_cursors_with(|map, head, _| {
13505                (
13506                    movement::line_end(map, head, action.stop_at_soft_wraps),
13507                    SelectionGoal::None,
13508                )
13509            });
13510        })
13511    }
13512
13513    pub fn select_to_end_of_line(
13514        &mut self,
13515        action: &SelectToEndOfLine,
13516        window: &mut Window,
13517        cx: &mut Context<Self>,
13518    ) {
13519        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13520        self.change_selections(Default::default(), window, cx, |s| {
13521            s.move_heads_with(|map, head, _| {
13522                (
13523                    movement::line_end(map, head, action.stop_at_soft_wraps),
13524                    SelectionGoal::None,
13525                )
13526            });
13527        })
13528    }
13529
13530    pub fn delete_to_end_of_line(
13531        &mut self,
13532        _: &DeleteToEndOfLine,
13533        window: &mut Window,
13534        cx: &mut Context<Self>,
13535    ) {
13536        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13537        self.transact(window, cx, |this, window, cx| {
13538            this.select_to_end_of_line(
13539                &SelectToEndOfLine {
13540                    stop_at_soft_wraps: false,
13541                },
13542                window,
13543                cx,
13544            );
13545            this.delete(&Delete, window, cx);
13546        });
13547    }
13548
13549    pub fn cut_to_end_of_line(
13550        &mut self,
13551        action: &CutToEndOfLine,
13552        window: &mut Window,
13553        cx: &mut Context<Self>,
13554    ) {
13555        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13556        self.transact(window, cx, |this, window, cx| {
13557            this.select_to_end_of_line(
13558                &SelectToEndOfLine {
13559                    stop_at_soft_wraps: false,
13560                },
13561                window,
13562                cx,
13563            );
13564            if !action.stop_at_newlines {
13565                this.change_selections(Default::default(), window, cx, |s| {
13566                    s.move_with(|_, sel| {
13567                        if sel.is_empty() {
13568                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13569                        }
13570                    });
13571                });
13572            }
13573            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13574            let item = this.cut_common(false, window, cx);
13575            cx.write_to_clipboard(item);
13576        });
13577    }
13578
13579    pub fn move_to_start_of_paragraph(
13580        &mut self,
13581        _: &MoveToStartOfParagraph,
13582        window: &mut Window,
13583        cx: &mut Context<Self>,
13584    ) {
13585        if matches!(self.mode, EditorMode::SingleLine) {
13586            cx.propagate();
13587            return;
13588        }
13589        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13590        self.change_selections(Default::default(), window, cx, |s| {
13591            s.move_with(|map, selection| {
13592                selection.collapse_to(
13593                    movement::start_of_paragraph(map, selection.head(), 1),
13594                    SelectionGoal::None,
13595                )
13596            });
13597        })
13598    }
13599
13600    pub fn move_to_end_of_paragraph(
13601        &mut self,
13602        _: &MoveToEndOfParagraph,
13603        window: &mut Window,
13604        cx: &mut Context<Self>,
13605    ) {
13606        if matches!(self.mode, EditorMode::SingleLine) {
13607            cx.propagate();
13608            return;
13609        }
13610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13611        self.change_selections(Default::default(), window, cx, |s| {
13612            s.move_with(|map, selection| {
13613                selection.collapse_to(
13614                    movement::end_of_paragraph(map, selection.head(), 1),
13615                    SelectionGoal::None,
13616                )
13617            });
13618        })
13619    }
13620
13621    pub fn select_to_start_of_paragraph(
13622        &mut self,
13623        _: &SelectToStartOfParagraph,
13624        window: &mut Window,
13625        cx: &mut Context<Self>,
13626    ) {
13627        if matches!(self.mode, EditorMode::SingleLine) {
13628            cx.propagate();
13629            return;
13630        }
13631        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13632        self.change_selections(Default::default(), window, cx, |s| {
13633            s.move_heads_with(|map, head, _| {
13634                (
13635                    movement::start_of_paragraph(map, head, 1),
13636                    SelectionGoal::None,
13637                )
13638            });
13639        })
13640    }
13641
13642    pub fn select_to_end_of_paragraph(
13643        &mut self,
13644        _: &SelectToEndOfParagraph,
13645        window: &mut Window,
13646        cx: &mut Context<Self>,
13647    ) {
13648        if matches!(self.mode, EditorMode::SingleLine) {
13649            cx.propagate();
13650            return;
13651        }
13652        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13653        self.change_selections(Default::default(), window, cx, |s| {
13654            s.move_heads_with(|map, head, _| {
13655                (
13656                    movement::end_of_paragraph(map, head, 1),
13657                    SelectionGoal::None,
13658                )
13659            });
13660        })
13661    }
13662
13663    pub fn move_to_start_of_excerpt(
13664        &mut self,
13665        _: &MoveToStartOfExcerpt,
13666        window: &mut Window,
13667        cx: &mut Context<Self>,
13668    ) {
13669        if matches!(self.mode, EditorMode::SingleLine) {
13670            cx.propagate();
13671            return;
13672        }
13673        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13674        self.change_selections(Default::default(), window, cx, |s| {
13675            s.move_with(|map, selection| {
13676                selection.collapse_to(
13677                    movement::start_of_excerpt(
13678                        map,
13679                        selection.head(),
13680                        workspace::searchable::Direction::Prev,
13681                    ),
13682                    SelectionGoal::None,
13683                )
13684            });
13685        })
13686    }
13687
13688    pub fn move_to_start_of_next_excerpt(
13689        &mut self,
13690        _: &MoveToStartOfNextExcerpt,
13691        window: &mut Window,
13692        cx: &mut Context<Self>,
13693    ) {
13694        if matches!(self.mode, EditorMode::SingleLine) {
13695            cx.propagate();
13696            return;
13697        }
13698
13699        self.change_selections(Default::default(), window, cx, |s| {
13700            s.move_with(|map, selection| {
13701                selection.collapse_to(
13702                    movement::start_of_excerpt(
13703                        map,
13704                        selection.head(),
13705                        workspace::searchable::Direction::Next,
13706                    ),
13707                    SelectionGoal::None,
13708                )
13709            });
13710        })
13711    }
13712
13713    pub fn move_to_end_of_excerpt(
13714        &mut self,
13715        _: &MoveToEndOfExcerpt,
13716        window: &mut Window,
13717        cx: &mut Context<Self>,
13718    ) {
13719        if matches!(self.mode, EditorMode::SingleLine) {
13720            cx.propagate();
13721            return;
13722        }
13723        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13724        self.change_selections(Default::default(), window, cx, |s| {
13725            s.move_with(|map, selection| {
13726                selection.collapse_to(
13727                    movement::end_of_excerpt(
13728                        map,
13729                        selection.head(),
13730                        workspace::searchable::Direction::Next,
13731                    ),
13732                    SelectionGoal::None,
13733                )
13734            });
13735        })
13736    }
13737
13738    pub fn move_to_end_of_previous_excerpt(
13739        &mut self,
13740        _: &MoveToEndOfPreviousExcerpt,
13741        window: &mut Window,
13742        cx: &mut Context<Self>,
13743    ) {
13744        if matches!(self.mode, EditorMode::SingleLine) {
13745            cx.propagate();
13746            return;
13747        }
13748        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13749        self.change_selections(Default::default(), window, cx, |s| {
13750            s.move_with(|map, selection| {
13751                selection.collapse_to(
13752                    movement::end_of_excerpt(
13753                        map,
13754                        selection.head(),
13755                        workspace::searchable::Direction::Prev,
13756                    ),
13757                    SelectionGoal::None,
13758                )
13759            });
13760        })
13761    }
13762
13763    pub fn select_to_start_of_excerpt(
13764        &mut self,
13765        _: &SelectToStartOfExcerpt,
13766        window: &mut Window,
13767        cx: &mut Context<Self>,
13768    ) {
13769        if matches!(self.mode, EditorMode::SingleLine) {
13770            cx.propagate();
13771            return;
13772        }
13773        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13774        self.change_selections(Default::default(), window, cx, |s| {
13775            s.move_heads_with(|map, head, _| {
13776                (
13777                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13778                    SelectionGoal::None,
13779                )
13780            });
13781        })
13782    }
13783
13784    pub fn select_to_start_of_next_excerpt(
13785        &mut self,
13786        _: &SelectToStartOfNextExcerpt,
13787        window: &mut Window,
13788        cx: &mut Context<Self>,
13789    ) {
13790        if matches!(self.mode, EditorMode::SingleLine) {
13791            cx.propagate();
13792            return;
13793        }
13794        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13795        self.change_selections(Default::default(), window, cx, |s| {
13796            s.move_heads_with(|map, head, _| {
13797                (
13798                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13799                    SelectionGoal::None,
13800                )
13801            });
13802        })
13803    }
13804
13805    pub fn select_to_end_of_excerpt(
13806        &mut self,
13807        _: &SelectToEndOfExcerpt,
13808        window: &mut Window,
13809        cx: &mut Context<Self>,
13810    ) {
13811        if matches!(self.mode, EditorMode::SingleLine) {
13812            cx.propagate();
13813            return;
13814        }
13815        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13816        self.change_selections(Default::default(), window, cx, |s| {
13817            s.move_heads_with(|map, head, _| {
13818                (
13819                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13820                    SelectionGoal::None,
13821                )
13822            });
13823        })
13824    }
13825
13826    pub fn select_to_end_of_previous_excerpt(
13827        &mut self,
13828        _: &SelectToEndOfPreviousExcerpt,
13829        window: &mut Window,
13830        cx: &mut Context<Self>,
13831    ) {
13832        if matches!(self.mode, EditorMode::SingleLine) {
13833            cx.propagate();
13834            return;
13835        }
13836        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13837        self.change_selections(Default::default(), window, cx, |s| {
13838            s.move_heads_with(|map, head, _| {
13839                (
13840                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13841                    SelectionGoal::None,
13842                )
13843            });
13844        })
13845    }
13846
13847    pub fn move_to_beginning(
13848        &mut self,
13849        _: &MoveToBeginning,
13850        window: &mut Window,
13851        cx: &mut Context<Self>,
13852    ) {
13853        if matches!(self.mode, EditorMode::SingleLine) {
13854            cx.propagate();
13855            return;
13856        }
13857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13858        self.change_selections(Default::default(), window, cx, |s| {
13859            s.select_ranges(vec![0..0]);
13860        });
13861    }
13862
13863    pub fn select_to_beginning(
13864        &mut self,
13865        _: &SelectToBeginning,
13866        window: &mut Window,
13867        cx: &mut Context<Self>,
13868    ) {
13869        let mut selection = self.selections.last::<Point>(cx);
13870        selection.set_head(Point::zero(), SelectionGoal::None);
13871        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13872        self.change_selections(Default::default(), window, cx, |s| {
13873            s.select(vec![selection]);
13874        });
13875    }
13876
13877    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13878        if matches!(self.mode, EditorMode::SingleLine) {
13879            cx.propagate();
13880            return;
13881        }
13882        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13883        let cursor = self.buffer.read(cx).read(cx).len();
13884        self.change_selections(Default::default(), window, cx, |s| {
13885            s.select_ranges(vec![cursor..cursor])
13886        });
13887    }
13888
13889    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13890        self.nav_history = nav_history;
13891    }
13892
13893    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13894        self.nav_history.as_ref()
13895    }
13896
13897    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13898        self.push_to_nav_history(
13899            self.selections.newest_anchor().head(),
13900            None,
13901            false,
13902            true,
13903            cx,
13904        );
13905    }
13906
13907    fn push_to_nav_history(
13908        &mut self,
13909        cursor_anchor: Anchor,
13910        new_position: Option<Point>,
13911        is_deactivate: bool,
13912        always: bool,
13913        cx: &mut Context<Self>,
13914    ) {
13915        if let Some(nav_history) = self.nav_history.as_mut() {
13916            let buffer = self.buffer.read(cx).read(cx);
13917            let cursor_position = cursor_anchor.to_point(&buffer);
13918            let scroll_state = self.scroll_manager.anchor();
13919            let scroll_top_row = scroll_state.top_row(&buffer);
13920            drop(buffer);
13921
13922            if let Some(new_position) = new_position {
13923                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13924                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13925                    return;
13926                }
13927            }
13928
13929            nav_history.push(
13930                Some(NavigationData {
13931                    cursor_anchor,
13932                    cursor_position,
13933                    scroll_anchor: scroll_state,
13934                    scroll_top_row,
13935                }),
13936                cx,
13937            );
13938            cx.emit(EditorEvent::PushedToNavHistory {
13939                anchor: cursor_anchor,
13940                is_deactivate,
13941            })
13942        }
13943    }
13944
13945    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13947        let buffer = self.buffer.read(cx).snapshot(cx);
13948        let mut selection = self.selections.first::<usize>(cx);
13949        selection.set_head(buffer.len(), SelectionGoal::None);
13950        self.change_selections(Default::default(), window, cx, |s| {
13951            s.select(vec![selection]);
13952        });
13953    }
13954
13955    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13957        let end = self.buffer.read(cx).read(cx).len();
13958        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13959            s.select_ranges(vec![0..end]);
13960        });
13961    }
13962
13963    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13964        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13965        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13966        let mut selections = self.selections.all::<Point>(cx);
13967        let max_point = display_map.buffer_snapshot.max_point();
13968        for selection in &mut selections {
13969            let rows = selection.spanned_rows(true, &display_map);
13970            selection.start = Point::new(rows.start.0, 0);
13971            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13972            selection.reversed = false;
13973        }
13974        self.change_selections(Default::default(), window, cx, |s| {
13975            s.select(selections);
13976        });
13977    }
13978
13979    pub fn split_selection_into_lines(
13980        &mut self,
13981        action: &SplitSelectionIntoLines,
13982        window: &mut Window,
13983        cx: &mut Context<Self>,
13984    ) {
13985        let selections = self
13986            .selections
13987            .all::<Point>(cx)
13988            .into_iter()
13989            .map(|selection| selection.start..selection.end)
13990            .collect::<Vec<_>>();
13991        self.unfold_ranges(&selections, true, true, cx);
13992
13993        let mut new_selection_ranges = Vec::new();
13994        {
13995            let buffer = self.buffer.read(cx).read(cx);
13996            for selection in selections {
13997                for row in selection.start.row..selection.end.row {
13998                    let line_start = Point::new(row, 0);
13999                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14000
14001                    if action.keep_selections {
14002                        // Keep the selection range for each line
14003                        let selection_start = if row == selection.start.row {
14004                            selection.start
14005                        } else {
14006                            line_start
14007                        };
14008                        new_selection_ranges.push(selection_start..line_end);
14009                    } else {
14010                        // Collapse to cursor at end of line
14011                        new_selection_ranges.push(line_end..line_end);
14012                    }
14013                }
14014
14015                let is_multiline_selection = selection.start.row != selection.end.row;
14016                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14017                // so this action feels more ergonomic when paired with other selection operations
14018                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14019                if !should_skip_last {
14020                    if action.keep_selections {
14021                        if is_multiline_selection {
14022                            let line_start = Point::new(selection.end.row, 0);
14023                            new_selection_ranges.push(line_start..selection.end);
14024                        } else {
14025                            new_selection_ranges.push(selection.start..selection.end);
14026                        }
14027                    } else {
14028                        new_selection_ranges.push(selection.end..selection.end);
14029                    }
14030                }
14031            }
14032        }
14033        self.change_selections(Default::default(), window, cx, |s| {
14034            s.select_ranges(new_selection_ranges);
14035        });
14036    }
14037
14038    pub fn add_selection_above(
14039        &mut self,
14040        _: &AddSelectionAbove,
14041        window: &mut Window,
14042        cx: &mut Context<Self>,
14043    ) {
14044        self.add_selection(true, window, cx);
14045    }
14046
14047    pub fn add_selection_below(
14048        &mut self,
14049        _: &AddSelectionBelow,
14050        window: &mut Window,
14051        cx: &mut Context<Self>,
14052    ) {
14053        self.add_selection(false, window, cx);
14054    }
14055
14056    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
14057        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14058
14059        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14060        let all_selections = self.selections.all::<Point>(cx);
14061        let text_layout_details = self.text_layout_details(window);
14062
14063        let (mut columnar_selections, new_selections_to_columnarize) = {
14064            if let Some(state) = self.add_selections_state.as_ref() {
14065                let columnar_selection_ids: HashSet<_> = state
14066                    .groups
14067                    .iter()
14068                    .flat_map(|group| group.stack.iter())
14069                    .copied()
14070                    .collect();
14071
14072                all_selections
14073                    .into_iter()
14074                    .partition(|s| columnar_selection_ids.contains(&s.id))
14075            } else {
14076                (Vec::new(), all_selections)
14077            }
14078        };
14079
14080        let mut state = self
14081            .add_selections_state
14082            .take()
14083            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14084
14085        for selection in new_selections_to_columnarize {
14086            let range = selection.display_range(&display_map).sorted();
14087            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14088            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14089            let positions = start_x.min(end_x)..start_x.max(end_x);
14090            let mut stack = Vec::new();
14091            for row in range.start.row().0..=range.end.row().0 {
14092                if let Some(selection) = self.selections.build_columnar_selection(
14093                    &display_map,
14094                    DisplayRow(row),
14095                    &positions,
14096                    selection.reversed,
14097                    &text_layout_details,
14098                ) {
14099                    stack.push(selection.id);
14100                    columnar_selections.push(selection);
14101                }
14102            }
14103            if !stack.is_empty() {
14104                if above {
14105                    stack.reverse();
14106                }
14107                state.groups.push(AddSelectionsGroup { above, stack });
14108            }
14109        }
14110
14111        let mut final_selections = Vec::new();
14112        let end_row = if above {
14113            DisplayRow(0)
14114        } else {
14115            display_map.max_point().row()
14116        };
14117
14118        let mut last_added_item_per_group = HashMap::default();
14119        for group in state.groups.iter_mut() {
14120            if let Some(last_id) = group.stack.last() {
14121                last_added_item_per_group.insert(*last_id, group);
14122            }
14123        }
14124
14125        for selection in columnar_selections {
14126            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14127                if above == group.above {
14128                    let range = selection.display_range(&display_map).sorted();
14129                    debug_assert_eq!(range.start.row(), range.end.row());
14130                    let mut row = range.start.row();
14131                    let positions =
14132                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14133                            px(start)..px(end)
14134                        } else {
14135                            let start_x =
14136                                display_map.x_for_display_point(range.start, &text_layout_details);
14137                            let end_x =
14138                                display_map.x_for_display_point(range.end, &text_layout_details);
14139                            start_x.min(end_x)..start_x.max(end_x)
14140                        };
14141
14142                    let mut maybe_new_selection = None;
14143                    while row != end_row {
14144                        if above {
14145                            row.0 -= 1;
14146                        } else {
14147                            row.0 += 1;
14148                        }
14149                        if let Some(new_selection) = self.selections.build_columnar_selection(
14150                            &display_map,
14151                            row,
14152                            &positions,
14153                            selection.reversed,
14154                            &text_layout_details,
14155                        ) {
14156                            maybe_new_selection = Some(new_selection);
14157                            break;
14158                        }
14159                    }
14160
14161                    if let Some(new_selection) = maybe_new_selection {
14162                        group.stack.push(new_selection.id);
14163                        if above {
14164                            final_selections.push(new_selection);
14165                            final_selections.push(selection);
14166                        } else {
14167                            final_selections.push(selection);
14168                            final_selections.push(new_selection);
14169                        }
14170                    } else {
14171                        final_selections.push(selection);
14172                    }
14173                } else {
14174                    group.stack.pop();
14175                }
14176            } else {
14177                final_selections.push(selection);
14178            }
14179        }
14180
14181        self.change_selections(Default::default(), window, cx, |s| {
14182            s.select(final_selections);
14183        });
14184
14185        let final_selection_ids: HashSet<_> = self
14186            .selections
14187            .all::<Point>(cx)
14188            .iter()
14189            .map(|s| s.id)
14190            .collect();
14191        state.groups.retain_mut(|group| {
14192            // selections might get merged above so we remove invalid items from stacks
14193            group.stack.retain(|id| final_selection_ids.contains(id));
14194
14195            // single selection in stack can be treated as initial state
14196            group.stack.len() > 1
14197        });
14198
14199        if !state.groups.is_empty() {
14200            self.add_selections_state = Some(state);
14201        }
14202    }
14203
14204    fn select_match_ranges(
14205        &mut self,
14206        range: Range<usize>,
14207        reversed: bool,
14208        replace_newest: bool,
14209        auto_scroll: Option<Autoscroll>,
14210        window: &mut Window,
14211        cx: &mut Context<Editor>,
14212    ) {
14213        self.unfold_ranges(
14214            std::slice::from_ref(&range),
14215            false,
14216            auto_scroll.is_some(),
14217            cx,
14218        );
14219        let effects = if let Some(scroll) = auto_scroll {
14220            SelectionEffects::scroll(scroll)
14221        } else {
14222            SelectionEffects::no_scroll()
14223        };
14224        self.change_selections(effects, window, cx, |s| {
14225            if replace_newest {
14226                s.delete(s.newest_anchor().id);
14227            }
14228            if reversed {
14229                s.insert_range(range.end..range.start);
14230            } else {
14231                s.insert_range(range);
14232            }
14233        });
14234    }
14235
14236    pub fn select_next_match_internal(
14237        &mut self,
14238        display_map: &DisplaySnapshot,
14239        replace_newest: bool,
14240        autoscroll: Option<Autoscroll>,
14241        window: &mut Window,
14242        cx: &mut Context<Self>,
14243    ) -> Result<()> {
14244        let buffer = &display_map.buffer_snapshot;
14245        let mut selections = self.selections.all::<usize>(cx);
14246        if let Some(mut select_next_state) = self.select_next_state.take() {
14247            let query = &select_next_state.query;
14248            if !select_next_state.done {
14249                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14250                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14251                let mut next_selected_range = None;
14252
14253                let bytes_after_last_selection =
14254                    buffer.bytes_in_range(last_selection.end..buffer.len());
14255                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14256                let query_matches = query
14257                    .stream_find_iter(bytes_after_last_selection)
14258                    .map(|result| (last_selection.end, result))
14259                    .chain(
14260                        query
14261                            .stream_find_iter(bytes_before_first_selection)
14262                            .map(|result| (0, result)),
14263                    );
14264
14265                for (start_offset, query_match) in query_matches {
14266                    let query_match = query_match.unwrap(); // can only fail due to I/O
14267                    let offset_range =
14268                        start_offset + query_match.start()..start_offset + query_match.end();
14269
14270                    if !select_next_state.wordwise
14271                        || (!buffer.is_inside_word(offset_range.start, None)
14272                            && !buffer.is_inside_word(offset_range.end, None))
14273                    {
14274                        // TODO: This is n^2, because we might check all the selections
14275                        if !selections
14276                            .iter()
14277                            .any(|selection| selection.range().overlaps(&offset_range))
14278                        {
14279                            next_selected_range = Some(offset_range);
14280                            break;
14281                        }
14282                    }
14283                }
14284
14285                if let Some(next_selected_range) = next_selected_range {
14286                    self.select_match_ranges(
14287                        next_selected_range,
14288                        last_selection.reversed,
14289                        replace_newest,
14290                        autoscroll,
14291                        window,
14292                        cx,
14293                    );
14294                } else {
14295                    select_next_state.done = true;
14296                }
14297            }
14298
14299            self.select_next_state = Some(select_next_state);
14300        } else {
14301            let mut only_carets = true;
14302            let mut same_text_selected = true;
14303            let mut selected_text = None;
14304
14305            let mut selections_iter = selections.iter().peekable();
14306            while let Some(selection) = selections_iter.next() {
14307                if selection.start != selection.end {
14308                    only_carets = false;
14309                }
14310
14311                if same_text_selected {
14312                    if selected_text.is_none() {
14313                        selected_text =
14314                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14315                    }
14316
14317                    if let Some(next_selection) = selections_iter.peek() {
14318                        if next_selection.range().len() == selection.range().len() {
14319                            let next_selected_text = buffer
14320                                .text_for_range(next_selection.range())
14321                                .collect::<String>();
14322                            if Some(next_selected_text) != selected_text {
14323                                same_text_selected = false;
14324                                selected_text = None;
14325                            }
14326                        } else {
14327                            same_text_selected = false;
14328                            selected_text = None;
14329                        }
14330                    }
14331                }
14332            }
14333
14334            if only_carets {
14335                for selection in &mut selections {
14336                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14337                    selection.start = word_range.start;
14338                    selection.end = word_range.end;
14339                    selection.goal = SelectionGoal::None;
14340                    selection.reversed = false;
14341                    self.select_match_ranges(
14342                        selection.start..selection.end,
14343                        selection.reversed,
14344                        replace_newest,
14345                        autoscroll,
14346                        window,
14347                        cx,
14348                    );
14349                }
14350
14351                if selections.len() == 1 {
14352                    let selection = selections
14353                        .last()
14354                        .expect("ensured that there's only one selection");
14355                    let query = buffer
14356                        .text_for_range(selection.start..selection.end)
14357                        .collect::<String>();
14358                    let is_empty = query.is_empty();
14359                    let select_state = SelectNextState {
14360                        query: AhoCorasick::new(&[query])?,
14361                        wordwise: true,
14362                        done: is_empty,
14363                    };
14364                    self.select_next_state = Some(select_state);
14365                } else {
14366                    self.select_next_state = None;
14367                }
14368            } else if let Some(selected_text) = selected_text {
14369                self.select_next_state = Some(SelectNextState {
14370                    query: AhoCorasick::new(&[selected_text])?,
14371                    wordwise: false,
14372                    done: false,
14373                });
14374                self.select_next_match_internal(
14375                    display_map,
14376                    replace_newest,
14377                    autoscroll,
14378                    window,
14379                    cx,
14380                )?;
14381            }
14382        }
14383        Ok(())
14384    }
14385
14386    pub fn select_all_matches(
14387        &mut self,
14388        _action: &SelectAllMatches,
14389        window: &mut Window,
14390        cx: &mut Context<Self>,
14391    ) -> Result<()> {
14392        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14393
14394        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14395
14396        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14397        let Some(select_next_state) = self.select_next_state.as_mut() else {
14398            return Ok(());
14399        };
14400        if select_next_state.done {
14401            return Ok(());
14402        }
14403
14404        let mut new_selections = Vec::new();
14405
14406        let reversed = self.selections.oldest::<usize>(cx).reversed;
14407        let buffer = &display_map.buffer_snapshot;
14408        let query_matches = select_next_state
14409            .query
14410            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14411
14412        for query_match in query_matches.into_iter() {
14413            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14414            let offset_range = if reversed {
14415                query_match.end()..query_match.start()
14416            } else {
14417                query_match.start()..query_match.end()
14418            };
14419
14420            if !select_next_state.wordwise
14421                || (!buffer.is_inside_word(offset_range.start, None)
14422                    && !buffer.is_inside_word(offset_range.end, None))
14423            {
14424                new_selections.push(offset_range.start..offset_range.end);
14425            }
14426        }
14427
14428        select_next_state.done = true;
14429
14430        if new_selections.is_empty() {
14431            log::error!("bug: new_selections is empty in select_all_matches");
14432            return Ok(());
14433        }
14434
14435        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14436        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14437            selections.select_ranges(new_selections)
14438        });
14439
14440        Ok(())
14441    }
14442
14443    pub fn select_next(
14444        &mut self,
14445        action: &SelectNext,
14446        window: &mut Window,
14447        cx: &mut Context<Self>,
14448    ) -> Result<()> {
14449        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14450        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14451        self.select_next_match_internal(
14452            &display_map,
14453            action.replace_newest,
14454            Some(Autoscroll::newest()),
14455            window,
14456            cx,
14457        )?;
14458        Ok(())
14459    }
14460
14461    pub fn select_previous(
14462        &mut self,
14463        action: &SelectPrevious,
14464        window: &mut Window,
14465        cx: &mut Context<Self>,
14466    ) -> Result<()> {
14467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14468        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14469        let buffer = &display_map.buffer_snapshot;
14470        let mut selections = self.selections.all::<usize>(cx);
14471        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14472            let query = &select_prev_state.query;
14473            if !select_prev_state.done {
14474                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14475                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14476                let mut next_selected_range = None;
14477                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14478                let bytes_before_last_selection =
14479                    buffer.reversed_bytes_in_range(0..last_selection.start);
14480                let bytes_after_first_selection =
14481                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14482                let query_matches = query
14483                    .stream_find_iter(bytes_before_last_selection)
14484                    .map(|result| (last_selection.start, result))
14485                    .chain(
14486                        query
14487                            .stream_find_iter(bytes_after_first_selection)
14488                            .map(|result| (buffer.len(), result)),
14489                    );
14490                for (end_offset, query_match) in query_matches {
14491                    let query_match = query_match.unwrap(); // can only fail due to I/O
14492                    let offset_range =
14493                        end_offset - query_match.end()..end_offset - query_match.start();
14494
14495                    if !select_prev_state.wordwise
14496                        || (!buffer.is_inside_word(offset_range.start, None)
14497                            && !buffer.is_inside_word(offset_range.end, None))
14498                    {
14499                        next_selected_range = Some(offset_range);
14500                        break;
14501                    }
14502                }
14503
14504                if let Some(next_selected_range) = next_selected_range {
14505                    self.select_match_ranges(
14506                        next_selected_range,
14507                        last_selection.reversed,
14508                        action.replace_newest,
14509                        Some(Autoscroll::newest()),
14510                        window,
14511                        cx,
14512                    );
14513                } else {
14514                    select_prev_state.done = true;
14515                }
14516            }
14517
14518            self.select_prev_state = Some(select_prev_state);
14519        } else {
14520            let mut only_carets = true;
14521            let mut same_text_selected = true;
14522            let mut selected_text = None;
14523
14524            let mut selections_iter = selections.iter().peekable();
14525            while let Some(selection) = selections_iter.next() {
14526                if selection.start != selection.end {
14527                    only_carets = false;
14528                }
14529
14530                if same_text_selected {
14531                    if selected_text.is_none() {
14532                        selected_text =
14533                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14534                    }
14535
14536                    if let Some(next_selection) = selections_iter.peek() {
14537                        if next_selection.range().len() == selection.range().len() {
14538                            let next_selected_text = buffer
14539                                .text_for_range(next_selection.range())
14540                                .collect::<String>();
14541                            if Some(next_selected_text) != selected_text {
14542                                same_text_selected = false;
14543                                selected_text = None;
14544                            }
14545                        } else {
14546                            same_text_selected = false;
14547                            selected_text = None;
14548                        }
14549                    }
14550                }
14551            }
14552
14553            if only_carets {
14554                for selection in &mut selections {
14555                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14556                    selection.start = word_range.start;
14557                    selection.end = word_range.end;
14558                    selection.goal = SelectionGoal::None;
14559                    selection.reversed = false;
14560                    self.select_match_ranges(
14561                        selection.start..selection.end,
14562                        selection.reversed,
14563                        action.replace_newest,
14564                        Some(Autoscroll::newest()),
14565                        window,
14566                        cx,
14567                    );
14568                }
14569                if selections.len() == 1 {
14570                    let selection = selections
14571                        .last()
14572                        .expect("ensured that there's only one selection");
14573                    let query = buffer
14574                        .text_for_range(selection.start..selection.end)
14575                        .collect::<String>();
14576                    let is_empty = query.is_empty();
14577                    let select_state = SelectNextState {
14578                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14579                        wordwise: true,
14580                        done: is_empty,
14581                    };
14582                    self.select_prev_state = Some(select_state);
14583                } else {
14584                    self.select_prev_state = None;
14585                }
14586            } else if let Some(selected_text) = selected_text {
14587                self.select_prev_state = Some(SelectNextState {
14588                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14589                    wordwise: false,
14590                    done: false,
14591                });
14592                self.select_previous(action, window, cx)?;
14593            }
14594        }
14595        Ok(())
14596    }
14597
14598    pub fn find_next_match(
14599        &mut self,
14600        _: &FindNextMatch,
14601        window: &mut Window,
14602        cx: &mut Context<Self>,
14603    ) -> Result<()> {
14604        let selections = self.selections.disjoint_anchors_arc();
14605        match selections.first() {
14606            Some(first) if selections.len() >= 2 => {
14607                self.change_selections(Default::default(), window, cx, |s| {
14608                    s.select_ranges([first.range()]);
14609                });
14610            }
14611            _ => self.select_next(
14612                &SelectNext {
14613                    replace_newest: true,
14614                },
14615                window,
14616                cx,
14617            )?,
14618        }
14619        Ok(())
14620    }
14621
14622    pub fn find_previous_match(
14623        &mut self,
14624        _: &FindPreviousMatch,
14625        window: &mut Window,
14626        cx: &mut Context<Self>,
14627    ) -> Result<()> {
14628        let selections = self.selections.disjoint_anchors_arc();
14629        match selections.last() {
14630            Some(last) if selections.len() >= 2 => {
14631                self.change_selections(Default::default(), window, cx, |s| {
14632                    s.select_ranges([last.range()]);
14633                });
14634            }
14635            _ => self.select_previous(
14636                &SelectPrevious {
14637                    replace_newest: true,
14638                },
14639                window,
14640                cx,
14641            )?,
14642        }
14643        Ok(())
14644    }
14645
14646    pub fn toggle_comments(
14647        &mut self,
14648        action: &ToggleComments,
14649        window: &mut Window,
14650        cx: &mut Context<Self>,
14651    ) {
14652        if self.read_only(cx) {
14653            return;
14654        }
14655        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14656        let text_layout_details = &self.text_layout_details(window);
14657        self.transact(window, cx, |this, window, cx| {
14658            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14659            let mut edits = Vec::new();
14660            let mut selection_edit_ranges = Vec::new();
14661            let mut last_toggled_row = None;
14662            let snapshot = this.buffer.read(cx).read(cx);
14663            let empty_str: Arc<str> = Arc::default();
14664            let mut suffixes_inserted = Vec::new();
14665            let ignore_indent = action.ignore_indent;
14666
14667            fn comment_prefix_range(
14668                snapshot: &MultiBufferSnapshot,
14669                row: MultiBufferRow,
14670                comment_prefix: &str,
14671                comment_prefix_whitespace: &str,
14672                ignore_indent: bool,
14673            ) -> Range<Point> {
14674                let indent_size = if ignore_indent {
14675                    0
14676                } else {
14677                    snapshot.indent_size_for_line(row).len
14678                };
14679
14680                let start = Point::new(row.0, indent_size);
14681
14682                let mut line_bytes = snapshot
14683                    .bytes_in_range(start..snapshot.max_point())
14684                    .flatten()
14685                    .copied();
14686
14687                // If this line currently begins with the line comment prefix, then record
14688                // the range containing the prefix.
14689                if line_bytes
14690                    .by_ref()
14691                    .take(comment_prefix.len())
14692                    .eq(comment_prefix.bytes())
14693                {
14694                    // Include any whitespace that matches the comment prefix.
14695                    let matching_whitespace_len = line_bytes
14696                        .zip(comment_prefix_whitespace.bytes())
14697                        .take_while(|(a, b)| a == b)
14698                        .count() as u32;
14699                    let end = Point::new(
14700                        start.row,
14701                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14702                    );
14703                    start..end
14704                } else {
14705                    start..start
14706                }
14707            }
14708
14709            fn comment_suffix_range(
14710                snapshot: &MultiBufferSnapshot,
14711                row: MultiBufferRow,
14712                comment_suffix: &str,
14713                comment_suffix_has_leading_space: bool,
14714            ) -> Range<Point> {
14715                let end = Point::new(row.0, snapshot.line_len(row));
14716                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14717
14718                let mut line_end_bytes = snapshot
14719                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14720                    .flatten()
14721                    .copied();
14722
14723                let leading_space_len = if suffix_start_column > 0
14724                    && line_end_bytes.next() == Some(b' ')
14725                    && comment_suffix_has_leading_space
14726                {
14727                    1
14728                } else {
14729                    0
14730                };
14731
14732                // If this line currently begins with the line comment prefix, then record
14733                // the range containing the prefix.
14734                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14735                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14736                    start..end
14737                } else {
14738                    end..end
14739                }
14740            }
14741
14742            // TODO: Handle selections that cross excerpts
14743            for selection in &mut selections {
14744                let start_column = snapshot
14745                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14746                    .len;
14747                let language = if let Some(language) =
14748                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14749                {
14750                    language
14751                } else {
14752                    continue;
14753                };
14754
14755                selection_edit_ranges.clear();
14756
14757                // If multiple selections contain a given row, avoid processing that
14758                // row more than once.
14759                let mut start_row = MultiBufferRow(selection.start.row);
14760                if last_toggled_row == Some(start_row) {
14761                    start_row = start_row.next_row();
14762                }
14763                let end_row =
14764                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14765                        MultiBufferRow(selection.end.row - 1)
14766                    } else {
14767                        MultiBufferRow(selection.end.row)
14768                    };
14769                last_toggled_row = Some(end_row);
14770
14771                if start_row > end_row {
14772                    continue;
14773                }
14774
14775                // If the language has line comments, toggle those.
14776                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14777
14778                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14779                if ignore_indent {
14780                    full_comment_prefixes = full_comment_prefixes
14781                        .into_iter()
14782                        .map(|s| Arc::from(s.trim_end()))
14783                        .collect();
14784                }
14785
14786                if !full_comment_prefixes.is_empty() {
14787                    let first_prefix = full_comment_prefixes
14788                        .first()
14789                        .expect("prefixes is non-empty");
14790                    let prefix_trimmed_lengths = full_comment_prefixes
14791                        .iter()
14792                        .map(|p| p.trim_end_matches(' ').len())
14793                        .collect::<SmallVec<[usize; 4]>>();
14794
14795                    let mut all_selection_lines_are_comments = true;
14796
14797                    for row in start_row.0..=end_row.0 {
14798                        let row = MultiBufferRow(row);
14799                        if start_row < end_row && snapshot.is_line_blank(row) {
14800                            continue;
14801                        }
14802
14803                        let prefix_range = full_comment_prefixes
14804                            .iter()
14805                            .zip(prefix_trimmed_lengths.iter().copied())
14806                            .map(|(prefix, trimmed_prefix_len)| {
14807                                comment_prefix_range(
14808                                    snapshot.deref(),
14809                                    row,
14810                                    &prefix[..trimmed_prefix_len],
14811                                    &prefix[trimmed_prefix_len..],
14812                                    ignore_indent,
14813                                )
14814                            })
14815                            .max_by_key(|range| range.end.column - range.start.column)
14816                            .expect("prefixes is non-empty");
14817
14818                        if prefix_range.is_empty() {
14819                            all_selection_lines_are_comments = false;
14820                        }
14821
14822                        selection_edit_ranges.push(prefix_range);
14823                    }
14824
14825                    if all_selection_lines_are_comments {
14826                        edits.extend(
14827                            selection_edit_ranges
14828                                .iter()
14829                                .cloned()
14830                                .map(|range| (range, empty_str.clone())),
14831                        );
14832                    } else {
14833                        let min_column = selection_edit_ranges
14834                            .iter()
14835                            .map(|range| range.start.column)
14836                            .min()
14837                            .unwrap_or(0);
14838                        edits.extend(selection_edit_ranges.iter().map(|range| {
14839                            let position = Point::new(range.start.row, min_column);
14840                            (position..position, first_prefix.clone())
14841                        }));
14842                    }
14843                } else if let Some(BlockCommentConfig {
14844                    start: full_comment_prefix,
14845                    end: comment_suffix,
14846                    ..
14847                }) = language.block_comment()
14848                {
14849                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14850                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14851                    let prefix_range = comment_prefix_range(
14852                        snapshot.deref(),
14853                        start_row,
14854                        comment_prefix,
14855                        comment_prefix_whitespace,
14856                        ignore_indent,
14857                    );
14858                    let suffix_range = comment_suffix_range(
14859                        snapshot.deref(),
14860                        end_row,
14861                        comment_suffix.trim_start_matches(' '),
14862                        comment_suffix.starts_with(' '),
14863                    );
14864
14865                    if prefix_range.is_empty() || suffix_range.is_empty() {
14866                        edits.push((
14867                            prefix_range.start..prefix_range.start,
14868                            full_comment_prefix.clone(),
14869                        ));
14870                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14871                        suffixes_inserted.push((end_row, comment_suffix.len()));
14872                    } else {
14873                        edits.push((prefix_range, empty_str.clone()));
14874                        edits.push((suffix_range, empty_str.clone()));
14875                    }
14876                } else {
14877                    continue;
14878                }
14879            }
14880
14881            drop(snapshot);
14882            this.buffer.update(cx, |buffer, cx| {
14883                buffer.edit(edits, None, cx);
14884            });
14885
14886            // Adjust selections so that they end before any comment suffixes that
14887            // were inserted.
14888            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14889            let mut selections = this.selections.all::<Point>(cx);
14890            let snapshot = this.buffer.read(cx).read(cx);
14891            for selection in &mut selections {
14892                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14893                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14894                        Ordering::Less => {
14895                            suffixes_inserted.next();
14896                            continue;
14897                        }
14898                        Ordering::Greater => break,
14899                        Ordering::Equal => {
14900                            if selection.end.column == snapshot.line_len(row) {
14901                                if selection.is_empty() {
14902                                    selection.start.column -= suffix_len as u32;
14903                                }
14904                                selection.end.column -= suffix_len as u32;
14905                            }
14906                            break;
14907                        }
14908                    }
14909                }
14910            }
14911
14912            drop(snapshot);
14913            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14914
14915            let selections = this.selections.all::<Point>(cx);
14916            let selections_on_single_row = selections.windows(2).all(|selections| {
14917                selections[0].start.row == selections[1].start.row
14918                    && selections[0].end.row == selections[1].end.row
14919                    && selections[0].start.row == selections[0].end.row
14920            });
14921            let selections_selecting = selections
14922                .iter()
14923                .any(|selection| selection.start != selection.end);
14924            let advance_downwards = action.advance_downwards
14925                && selections_on_single_row
14926                && !selections_selecting
14927                && !matches!(this.mode, EditorMode::SingleLine);
14928
14929            if advance_downwards {
14930                let snapshot = this.buffer.read(cx).snapshot(cx);
14931
14932                this.change_selections(Default::default(), window, cx, |s| {
14933                    s.move_cursors_with(|display_snapshot, display_point, _| {
14934                        let mut point = display_point.to_point(display_snapshot);
14935                        point.row += 1;
14936                        point = snapshot.clip_point(point, Bias::Left);
14937                        let display_point = point.to_display_point(display_snapshot);
14938                        let goal = SelectionGoal::HorizontalPosition(
14939                            display_snapshot
14940                                .x_for_display_point(display_point, text_layout_details)
14941                                .into(),
14942                        );
14943                        (display_point, goal)
14944                    })
14945                });
14946            }
14947        });
14948    }
14949
14950    pub fn select_enclosing_symbol(
14951        &mut self,
14952        _: &SelectEnclosingSymbol,
14953        window: &mut Window,
14954        cx: &mut Context<Self>,
14955    ) {
14956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14957
14958        let buffer = self.buffer.read(cx).snapshot(cx);
14959        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14960
14961        fn update_selection(
14962            selection: &Selection<usize>,
14963            buffer_snap: &MultiBufferSnapshot,
14964        ) -> Option<Selection<usize>> {
14965            let cursor = selection.head();
14966            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14967            for symbol in symbols.iter().rev() {
14968                let start = symbol.range.start.to_offset(buffer_snap);
14969                let end = symbol.range.end.to_offset(buffer_snap);
14970                let new_range = start..end;
14971                if start < selection.start || end > selection.end {
14972                    return Some(Selection {
14973                        id: selection.id,
14974                        start: new_range.start,
14975                        end: new_range.end,
14976                        goal: SelectionGoal::None,
14977                        reversed: selection.reversed,
14978                    });
14979                }
14980            }
14981            None
14982        }
14983
14984        let mut selected_larger_symbol = false;
14985        let new_selections = old_selections
14986            .iter()
14987            .map(|selection| match update_selection(selection, &buffer) {
14988                Some(new_selection) => {
14989                    if new_selection.range() != selection.range() {
14990                        selected_larger_symbol = true;
14991                    }
14992                    new_selection
14993                }
14994                None => selection.clone(),
14995            })
14996            .collect::<Vec<_>>();
14997
14998        if selected_larger_symbol {
14999            self.change_selections(Default::default(), window, cx, |s| {
15000                s.select(new_selections);
15001            });
15002        }
15003    }
15004
15005    pub fn select_larger_syntax_node(
15006        &mut self,
15007        _: &SelectLargerSyntaxNode,
15008        window: &mut Window,
15009        cx: &mut Context<Self>,
15010    ) {
15011        let Some(visible_row_count) = self.visible_row_count() else {
15012            return;
15013        };
15014        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15015        if old_selections.is_empty() {
15016            return;
15017        }
15018
15019        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15020
15021        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15022        let buffer = self.buffer.read(cx).snapshot(cx);
15023
15024        let mut selected_larger_node = false;
15025        let mut new_selections = old_selections
15026            .iter()
15027            .map(|selection| {
15028                let old_range = selection.start..selection.end;
15029
15030                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15031                    // manually select word at selection
15032                    if ["string_content", "inline"].contains(&node.kind()) {
15033                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15034                        // ignore if word is already selected
15035                        if !word_range.is_empty() && old_range != word_range {
15036                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15037                            // only select word if start and end point belongs to same word
15038                            if word_range == last_word_range {
15039                                selected_larger_node = true;
15040                                return Selection {
15041                                    id: selection.id,
15042                                    start: word_range.start,
15043                                    end: word_range.end,
15044                                    goal: SelectionGoal::None,
15045                                    reversed: selection.reversed,
15046                                };
15047                            }
15048                        }
15049                    }
15050                }
15051
15052                let mut new_range = old_range.clone();
15053                while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
15054                {
15055                    new_range = match containing_range {
15056                        MultiOrSingleBufferOffsetRange::Single(_) => break,
15057                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15058                    };
15059                    if !node.is_named() {
15060                        continue;
15061                    }
15062                    if !display_map.intersects_fold(new_range.start)
15063                        && !display_map.intersects_fold(new_range.end)
15064                    {
15065                        break;
15066                    }
15067                }
15068
15069                selected_larger_node |= new_range != old_range;
15070                Selection {
15071                    id: selection.id,
15072                    start: new_range.start,
15073                    end: new_range.end,
15074                    goal: SelectionGoal::None,
15075                    reversed: selection.reversed,
15076                }
15077            })
15078            .collect::<Vec<_>>();
15079
15080        if !selected_larger_node {
15081            return; // don't put this call in the history
15082        }
15083
15084        // scroll based on transformation done to the last selection created by the user
15085        let (last_old, last_new) = old_selections
15086            .last()
15087            .zip(new_selections.last().cloned())
15088            .expect("old_selections isn't empty");
15089
15090        // revert selection
15091        let is_selection_reversed = {
15092            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15093            new_selections.last_mut().expect("checked above").reversed =
15094                should_newest_selection_be_reversed;
15095            should_newest_selection_be_reversed
15096        };
15097
15098        if selected_larger_node {
15099            self.select_syntax_node_history.disable_clearing = true;
15100            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15101                s.select(new_selections.clone());
15102            });
15103            self.select_syntax_node_history.disable_clearing = false;
15104        }
15105
15106        let start_row = last_new.start.to_display_point(&display_map).row().0;
15107        let end_row = last_new.end.to_display_point(&display_map).row().0;
15108        let selection_height = end_row - start_row + 1;
15109        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15110
15111        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15112        let scroll_behavior = if fits_on_the_screen {
15113            self.request_autoscroll(Autoscroll::fit(), cx);
15114            SelectSyntaxNodeScrollBehavior::FitSelection
15115        } else if is_selection_reversed {
15116            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15117            SelectSyntaxNodeScrollBehavior::CursorTop
15118        } else {
15119            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15120            SelectSyntaxNodeScrollBehavior::CursorBottom
15121        };
15122
15123        self.select_syntax_node_history.push((
15124            old_selections,
15125            scroll_behavior,
15126            is_selection_reversed,
15127        ));
15128    }
15129
15130    pub fn select_smaller_syntax_node(
15131        &mut self,
15132        _: &SelectSmallerSyntaxNode,
15133        window: &mut Window,
15134        cx: &mut Context<Self>,
15135    ) {
15136        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15137
15138        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15139            self.select_syntax_node_history.pop()
15140        {
15141            if let Some(selection) = selections.last_mut() {
15142                selection.reversed = is_selection_reversed;
15143            }
15144
15145            self.select_syntax_node_history.disable_clearing = true;
15146            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15147                s.select(selections.to_vec());
15148            });
15149            self.select_syntax_node_history.disable_clearing = false;
15150
15151            match scroll_behavior {
15152                SelectSyntaxNodeScrollBehavior::CursorTop => {
15153                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15154                }
15155                SelectSyntaxNodeScrollBehavior::FitSelection => {
15156                    self.request_autoscroll(Autoscroll::fit(), cx);
15157                }
15158                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15159                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15160                }
15161            }
15162        }
15163    }
15164
15165    pub fn unwrap_syntax_node(
15166        &mut self,
15167        _: &UnwrapSyntaxNode,
15168        window: &mut Window,
15169        cx: &mut Context<Self>,
15170    ) {
15171        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15172
15173        let buffer = self.buffer.read(cx).snapshot(cx);
15174        let selections = self
15175            .selections
15176            .all::<usize>(cx)
15177            .into_iter()
15178            // subtracting the offset requires sorting
15179            .sorted_by_key(|i| i.start);
15180
15181        let full_edits = selections
15182            .into_iter()
15183            .filter_map(|selection| {
15184                let child = if selection.is_empty()
15185                    && let Some((_, ancestor_range)) =
15186                        buffer.syntax_ancestor(selection.start..selection.end)
15187                {
15188                    match ancestor_range {
15189                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15190                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15191                    }
15192                } else {
15193                    selection.range()
15194                };
15195
15196                let mut parent = child.clone();
15197                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15198                    parent = match ancestor_range {
15199                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15200                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15201                    };
15202                    if parent.start < child.start || parent.end > child.end {
15203                        break;
15204                    }
15205                }
15206
15207                if parent == child {
15208                    return None;
15209                }
15210                let text = buffer.text_for_range(child).collect::<String>();
15211                Some((selection.id, parent, text))
15212            })
15213            .collect::<Vec<_>>();
15214        if full_edits.is_empty() {
15215            return;
15216        }
15217
15218        self.transact(window, cx, |this, window, cx| {
15219            this.buffer.update(cx, |buffer, cx| {
15220                buffer.edit(
15221                    full_edits
15222                        .iter()
15223                        .map(|(_, p, t)| (p.clone(), t.clone()))
15224                        .collect::<Vec<_>>(),
15225                    None,
15226                    cx,
15227                );
15228            });
15229            this.change_selections(Default::default(), window, cx, |s| {
15230                let mut offset = 0;
15231                let mut selections = vec![];
15232                for (id, parent, text) in full_edits {
15233                    let start = parent.start - offset;
15234                    offset += parent.len() - text.len();
15235                    selections.push(Selection {
15236                        id,
15237                        start,
15238                        end: start + text.len(),
15239                        reversed: false,
15240                        goal: Default::default(),
15241                    });
15242                }
15243                s.select(selections);
15244            });
15245        });
15246    }
15247
15248    pub fn select_next_syntax_node(
15249        &mut self,
15250        _: &SelectNextSyntaxNode,
15251        window: &mut Window,
15252        cx: &mut Context<Self>,
15253    ) {
15254        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15255        if old_selections.is_empty() {
15256            return;
15257        }
15258
15259        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15260
15261        let buffer = self.buffer.read(cx).snapshot(cx);
15262        let mut selected_sibling = false;
15263
15264        let new_selections = old_selections
15265            .iter()
15266            .map(|selection| {
15267                let old_range = selection.start..selection.end;
15268
15269                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15270                    let new_range = node.byte_range();
15271                    selected_sibling = true;
15272                    Selection {
15273                        id: selection.id,
15274                        start: new_range.start,
15275                        end: new_range.end,
15276                        goal: SelectionGoal::None,
15277                        reversed: selection.reversed,
15278                    }
15279                } else {
15280                    selection.clone()
15281                }
15282            })
15283            .collect::<Vec<_>>();
15284
15285        if selected_sibling {
15286            self.change_selections(
15287                SelectionEffects::scroll(Autoscroll::fit()),
15288                window,
15289                cx,
15290                |s| {
15291                    s.select(new_selections);
15292                },
15293            );
15294        }
15295    }
15296
15297    pub fn select_prev_syntax_node(
15298        &mut self,
15299        _: &SelectPreviousSyntaxNode,
15300        window: &mut Window,
15301        cx: &mut Context<Self>,
15302    ) {
15303        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15304        if old_selections.is_empty() {
15305            return;
15306        }
15307
15308        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15309
15310        let buffer = self.buffer.read(cx).snapshot(cx);
15311        let mut selected_sibling = false;
15312
15313        let new_selections = old_selections
15314            .iter()
15315            .map(|selection| {
15316                let old_range = selection.start..selection.end;
15317
15318                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15319                    let new_range = node.byte_range();
15320                    selected_sibling = true;
15321                    Selection {
15322                        id: selection.id,
15323                        start: new_range.start,
15324                        end: new_range.end,
15325                        goal: SelectionGoal::None,
15326                        reversed: selection.reversed,
15327                    }
15328                } else {
15329                    selection.clone()
15330                }
15331            })
15332            .collect::<Vec<_>>();
15333
15334        if selected_sibling {
15335            self.change_selections(
15336                SelectionEffects::scroll(Autoscroll::fit()),
15337                window,
15338                cx,
15339                |s| {
15340                    s.select(new_selections);
15341                },
15342            );
15343        }
15344    }
15345
15346    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15347        if !EditorSettings::get_global(cx).gutter.runnables {
15348            self.clear_tasks();
15349            return Task::ready(());
15350        }
15351        let project = self.project().map(Entity::downgrade);
15352        let task_sources = self.lsp_task_sources(cx);
15353        let multi_buffer = self.buffer.downgrade();
15354        cx.spawn_in(window, async move |editor, cx| {
15355            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15356            let Some(project) = project.and_then(|p| p.upgrade()) else {
15357                return;
15358            };
15359            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15360                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15361            }) else {
15362                return;
15363            };
15364
15365            let hide_runnables = project
15366                .update(cx, |project, _| project.is_via_collab())
15367                .unwrap_or(true);
15368            if hide_runnables {
15369                return;
15370            }
15371            let new_rows =
15372                cx.background_spawn({
15373                    let snapshot = display_snapshot.clone();
15374                    async move {
15375                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15376                    }
15377                })
15378                    .await;
15379            let Ok(lsp_tasks) =
15380                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15381            else {
15382                return;
15383            };
15384            let lsp_tasks = lsp_tasks.await;
15385
15386            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15387                lsp_tasks
15388                    .into_iter()
15389                    .flat_map(|(kind, tasks)| {
15390                        tasks.into_iter().filter_map(move |(location, task)| {
15391                            Some((kind.clone(), location?, task))
15392                        })
15393                    })
15394                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15395                        let buffer = location.target.buffer;
15396                        let buffer_snapshot = buffer.read(cx).snapshot();
15397                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15398                            |(excerpt_id, snapshot, _)| {
15399                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15400                                    display_snapshot
15401                                        .buffer_snapshot
15402                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15403                                } else {
15404                                    None
15405                                }
15406                            },
15407                        );
15408                        if let Some(offset) = offset {
15409                            let task_buffer_range =
15410                                location.target.range.to_point(&buffer_snapshot);
15411                            let context_buffer_range =
15412                                task_buffer_range.to_offset(&buffer_snapshot);
15413                            let context_range = BufferOffset(context_buffer_range.start)
15414                                ..BufferOffset(context_buffer_range.end);
15415
15416                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15417                                .or_insert_with(|| RunnableTasks {
15418                                    templates: Vec::new(),
15419                                    offset,
15420                                    column: task_buffer_range.start.column,
15421                                    extra_variables: HashMap::default(),
15422                                    context_range,
15423                                })
15424                                .templates
15425                                .push((kind, task.original_task().clone()));
15426                        }
15427
15428                        acc
15429                    })
15430            }) else {
15431                return;
15432            };
15433
15434            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15435                buffer.language_settings(cx).tasks.prefer_lsp
15436            }) else {
15437                return;
15438            };
15439
15440            let rows = Self::runnable_rows(
15441                project,
15442                display_snapshot,
15443                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15444                new_rows,
15445                cx.clone(),
15446            )
15447            .await;
15448            editor
15449                .update(cx, |editor, _| {
15450                    editor.clear_tasks();
15451                    for (key, mut value) in rows {
15452                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15453                            value.templates.extend(lsp_tasks.templates);
15454                        }
15455
15456                        editor.insert_tasks(key, value);
15457                    }
15458                    for (key, value) in lsp_tasks_by_rows {
15459                        editor.insert_tasks(key, value);
15460                    }
15461                })
15462                .ok();
15463        })
15464    }
15465    fn fetch_runnable_ranges(
15466        snapshot: &DisplaySnapshot,
15467        range: Range<Anchor>,
15468    ) -> Vec<language::RunnableRange> {
15469        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15470    }
15471
15472    fn runnable_rows(
15473        project: Entity<Project>,
15474        snapshot: DisplaySnapshot,
15475        prefer_lsp: bool,
15476        runnable_ranges: Vec<RunnableRange>,
15477        cx: AsyncWindowContext,
15478    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15479        cx.spawn(async move |cx| {
15480            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15481            for mut runnable in runnable_ranges {
15482                let Some(tasks) = cx
15483                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15484                    .ok()
15485                else {
15486                    continue;
15487                };
15488                let mut tasks = tasks.await;
15489
15490                if prefer_lsp {
15491                    tasks.retain(|(task_kind, _)| {
15492                        !matches!(task_kind, TaskSourceKind::Language { .. })
15493                    });
15494                }
15495                if tasks.is_empty() {
15496                    continue;
15497                }
15498
15499                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15500                let Some(row) = snapshot
15501                    .buffer_snapshot
15502                    .buffer_line_for_row(MultiBufferRow(point.row))
15503                    .map(|(_, range)| range.start.row)
15504                else {
15505                    continue;
15506                };
15507
15508                let context_range =
15509                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15510                runnable_rows.push((
15511                    (runnable.buffer_id, row),
15512                    RunnableTasks {
15513                        templates: tasks,
15514                        offset: snapshot
15515                            .buffer_snapshot
15516                            .anchor_before(runnable.run_range.start),
15517                        context_range,
15518                        column: point.column,
15519                        extra_variables: runnable.extra_captures,
15520                    },
15521                ));
15522            }
15523            runnable_rows
15524        })
15525    }
15526
15527    fn templates_with_tags(
15528        project: &Entity<Project>,
15529        runnable: &mut Runnable,
15530        cx: &mut App,
15531    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15532        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15533            let (worktree_id, file) = project
15534                .buffer_for_id(runnable.buffer, cx)
15535                .and_then(|buffer| buffer.read(cx).file())
15536                .map(|file| (file.worktree_id(cx), file.clone()))
15537                .unzip();
15538
15539            (
15540                project.task_store().read(cx).task_inventory().cloned(),
15541                worktree_id,
15542                file,
15543            )
15544        });
15545
15546        let tags = mem::take(&mut runnable.tags);
15547        let language = runnable.language.clone();
15548        cx.spawn(async move |cx| {
15549            let mut templates_with_tags = Vec::new();
15550            if let Some(inventory) = inventory {
15551                for RunnableTag(tag) in tags {
15552                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15553                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15554                    }) else {
15555                        return templates_with_tags;
15556                    };
15557                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15558                        move |(_, template)| {
15559                            template.tags.iter().any(|source_tag| source_tag == &tag)
15560                        },
15561                    ));
15562                }
15563            }
15564            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15565
15566            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15567                // Strongest source wins; if we have worktree tag binding, prefer that to
15568                // global and language bindings;
15569                // if we have a global binding, prefer that to language binding.
15570                let first_mismatch = templates_with_tags
15571                    .iter()
15572                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15573                if let Some(index) = first_mismatch {
15574                    templates_with_tags.truncate(index);
15575                }
15576            }
15577
15578            templates_with_tags
15579        })
15580    }
15581
15582    pub fn move_to_enclosing_bracket(
15583        &mut self,
15584        _: &MoveToEnclosingBracket,
15585        window: &mut Window,
15586        cx: &mut Context<Self>,
15587    ) {
15588        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15589        self.change_selections(Default::default(), window, cx, |s| {
15590            s.move_offsets_with(|snapshot, selection| {
15591                let Some(enclosing_bracket_ranges) =
15592                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15593                else {
15594                    return;
15595                };
15596
15597                let mut best_length = usize::MAX;
15598                let mut best_inside = false;
15599                let mut best_in_bracket_range = false;
15600                let mut best_destination = None;
15601                for (open, close) in enclosing_bracket_ranges {
15602                    let close = close.to_inclusive();
15603                    let length = close.end() - open.start;
15604                    let inside = selection.start >= open.end && selection.end <= *close.start();
15605                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15606                        || close.contains(&selection.head());
15607
15608                    // If best is next to a bracket and current isn't, skip
15609                    if !in_bracket_range && best_in_bracket_range {
15610                        continue;
15611                    }
15612
15613                    // Prefer smaller lengths unless best is inside and current isn't
15614                    if length > best_length && (best_inside || !inside) {
15615                        continue;
15616                    }
15617
15618                    best_length = length;
15619                    best_inside = inside;
15620                    best_in_bracket_range = in_bracket_range;
15621                    best_destination = Some(
15622                        if close.contains(&selection.start) && close.contains(&selection.end) {
15623                            if inside { open.end } else { open.start }
15624                        } else if inside {
15625                            *close.start()
15626                        } else {
15627                            *close.end()
15628                        },
15629                    );
15630                }
15631
15632                if let Some(destination) = best_destination {
15633                    selection.collapse_to(destination, SelectionGoal::None);
15634                }
15635            })
15636        });
15637    }
15638
15639    pub fn undo_selection(
15640        &mut self,
15641        _: &UndoSelection,
15642        window: &mut Window,
15643        cx: &mut Context<Self>,
15644    ) {
15645        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15646        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15647            self.selection_history.mode = SelectionHistoryMode::Undoing;
15648            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15649                this.end_selection(window, cx);
15650                this.change_selections(
15651                    SelectionEffects::scroll(Autoscroll::newest()),
15652                    window,
15653                    cx,
15654                    |s| s.select_anchors(entry.selections.to_vec()),
15655                );
15656            });
15657            self.selection_history.mode = SelectionHistoryMode::Normal;
15658
15659            self.select_next_state = entry.select_next_state;
15660            self.select_prev_state = entry.select_prev_state;
15661            self.add_selections_state = entry.add_selections_state;
15662        }
15663    }
15664
15665    pub fn redo_selection(
15666        &mut self,
15667        _: &RedoSelection,
15668        window: &mut Window,
15669        cx: &mut Context<Self>,
15670    ) {
15671        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15672        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15673            self.selection_history.mode = SelectionHistoryMode::Redoing;
15674            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15675                this.end_selection(window, cx);
15676                this.change_selections(
15677                    SelectionEffects::scroll(Autoscroll::newest()),
15678                    window,
15679                    cx,
15680                    |s| s.select_anchors(entry.selections.to_vec()),
15681                );
15682            });
15683            self.selection_history.mode = SelectionHistoryMode::Normal;
15684
15685            self.select_next_state = entry.select_next_state;
15686            self.select_prev_state = entry.select_prev_state;
15687            self.add_selections_state = entry.add_selections_state;
15688        }
15689    }
15690
15691    pub fn expand_excerpts(
15692        &mut self,
15693        action: &ExpandExcerpts,
15694        _: &mut Window,
15695        cx: &mut Context<Self>,
15696    ) {
15697        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15698    }
15699
15700    pub fn expand_excerpts_down(
15701        &mut self,
15702        action: &ExpandExcerptsDown,
15703        _: &mut Window,
15704        cx: &mut Context<Self>,
15705    ) {
15706        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15707    }
15708
15709    pub fn expand_excerpts_up(
15710        &mut self,
15711        action: &ExpandExcerptsUp,
15712        _: &mut Window,
15713        cx: &mut Context<Self>,
15714    ) {
15715        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15716    }
15717
15718    pub fn expand_excerpts_for_direction(
15719        &mut self,
15720        lines: u32,
15721        direction: ExpandExcerptDirection,
15722
15723        cx: &mut Context<Self>,
15724    ) {
15725        let selections = self.selections.disjoint_anchors_arc();
15726
15727        let lines = if lines == 0 {
15728            EditorSettings::get_global(cx).expand_excerpt_lines
15729        } else {
15730            lines
15731        };
15732
15733        self.buffer.update(cx, |buffer, cx| {
15734            let snapshot = buffer.snapshot(cx);
15735            let mut excerpt_ids = selections
15736                .iter()
15737                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15738                .collect::<Vec<_>>();
15739            excerpt_ids.sort();
15740            excerpt_ids.dedup();
15741            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15742        })
15743    }
15744
15745    pub fn expand_excerpt(
15746        &mut self,
15747        excerpt: ExcerptId,
15748        direction: ExpandExcerptDirection,
15749        window: &mut Window,
15750        cx: &mut Context<Self>,
15751    ) {
15752        let current_scroll_position = self.scroll_position(cx);
15753        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15754        let mut should_scroll_up = false;
15755
15756        if direction == ExpandExcerptDirection::Down {
15757            let multi_buffer = self.buffer.read(cx);
15758            let snapshot = multi_buffer.snapshot(cx);
15759            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15760                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15761                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15762            {
15763                let buffer_snapshot = buffer.read(cx).snapshot();
15764                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15765                let last_row = buffer_snapshot.max_point().row;
15766                let lines_below = last_row.saturating_sub(excerpt_end_row);
15767                should_scroll_up = lines_below >= lines_to_expand;
15768            }
15769        }
15770
15771        self.buffer.update(cx, |buffer, cx| {
15772            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15773        });
15774
15775        if should_scroll_up {
15776            let new_scroll_position =
15777                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15778            self.set_scroll_position(new_scroll_position, window, cx);
15779        }
15780    }
15781
15782    pub fn go_to_singleton_buffer_point(
15783        &mut self,
15784        point: Point,
15785        window: &mut Window,
15786        cx: &mut Context<Self>,
15787    ) {
15788        self.go_to_singleton_buffer_range(point..point, window, cx);
15789    }
15790
15791    pub fn go_to_singleton_buffer_range(
15792        &mut self,
15793        range: Range<Point>,
15794        window: &mut Window,
15795        cx: &mut Context<Self>,
15796    ) {
15797        let multibuffer = self.buffer().read(cx);
15798        let Some(buffer) = multibuffer.as_singleton() else {
15799            return;
15800        };
15801        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15802            return;
15803        };
15804        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15805            return;
15806        };
15807        self.change_selections(
15808            SelectionEffects::default().nav_history(true),
15809            window,
15810            cx,
15811            |s| s.select_anchor_ranges([start..end]),
15812        );
15813    }
15814
15815    pub fn go_to_diagnostic(
15816        &mut self,
15817        action: &GoToDiagnostic,
15818        window: &mut Window,
15819        cx: &mut Context<Self>,
15820    ) {
15821        if !self.diagnostics_enabled() {
15822            return;
15823        }
15824        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15825        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15826    }
15827
15828    pub fn go_to_prev_diagnostic(
15829        &mut self,
15830        action: &GoToPreviousDiagnostic,
15831        window: &mut Window,
15832        cx: &mut Context<Self>,
15833    ) {
15834        if !self.diagnostics_enabled() {
15835            return;
15836        }
15837        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15838        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15839    }
15840
15841    pub fn go_to_diagnostic_impl(
15842        &mut self,
15843        direction: Direction,
15844        severity: GoToDiagnosticSeverityFilter,
15845        window: &mut Window,
15846        cx: &mut Context<Self>,
15847    ) {
15848        let buffer = self.buffer.read(cx).snapshot(cx);
15849        let selection = self.selections.newest::<usize>(cx);
15850
15851        let mut active_group_id = None;
15852        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15853            && active_group.active_range.start.to_offset(&buffer) == selection.start
15854        {
15855            active_group_id = Some(active_group.group_id);
15856        }
15857
15858        fn filtered(
15859            snapshot: EditorSnapshot,
15860            severity: GoToDiagnosticSeverityFilter,
15861            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15862        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15863            diagnostics
15864                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15865                .filter(|entry| entry.range.start != entry.range.end)
15866                .filter(|entry| !entry.diagnostic.is_unnecessary)
15867                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15868        }
15869
15870        let snapshot = self.snapshot(window, cx);
15871        let before = filtered(
15872            snapshot.clone(),
15873            severity,
15874            buffer
15875                .diagnostics_in_range(0..selection.start)
15876                .filter(|entry| entry.range.start <= selection.start),
15877        );
15878        let after = filtered(
15879            snapshot,
15880            severity,
15881            buffer
15882                .diagnostics_in_range(selection.start..buffer.len())
15883                .filter(|entry| entry.range.start >= selection.start),
15884        );
15885
15886        let mut found: Option<DiagnosticEntry<usize>> = None;
15887        if direction == Direction::Prev {
15888            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15889            {
15890                for diagnostic in prev_diagnostics.into_iter().rev() {
15891                    if diagnostic.range.start != selection.start
15892                        || active_group_id
15893                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15894                    {
15895                        found = Some(diagnostic);
15896                        break 'outer;
15897                    }
15898                }
15899            }
15900        } else {
15901            for diagnostic in after.chain(before) {
15902                if diagnostic.range.start != selection.start
15903                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15904                {
15905                    found = Some(diagnostic);
15906                    break;
15907                }
15908            }
15909        }
15910        let Some(next_diagnostic) = found else {
15911            return;
15912        };
15913
15914        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15915        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15916            return;
15917        };
15918        self.change_selections(Default::default(), window, cx, |s| {
15919            s.select_ranges(vec![
15920                next_diagnostic.range.start..next_diagnostic.range.start,
15921            ])
15922        });
15923        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15924        self.refresh_edit_prediction(false, true, window, cx);
15925    }
15926
15927    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
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::Next,
15935            window,
15936            cx,
15937        );
15938    }
15939
15940    pub fn go_to_hunk_before_or_after_position(
15941        &mut self,
15942        snapshot: &EditorSnapshot,
15943        position: Point,
15944        direction: Direction,
15945        window: &mut Window,
15946        cx: &mut Context<Editor>,
15947    ) {
15948        let row = if direction == Direction::Next {
15949            self.hunk_after_position(snapshot, position)
15950                .map(|hunk| hunk.row_range.start)
15951        } else {
15952            self.hunk_before_position(snapshot, position)
15953        };
15954
15955        if let Some(row) = row {
15956            let destination = Point::new(row.0, 0);
15957            let autoscroll = Autoscroll::center();
15958
15959            self.unfold_ranges(&[destination..destination], false, false, cx);
15960            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15961                s.select_ranges([destination..destination]);
15962            });
15963        }
15964    }
15965
15966    fn hunk_after_position(
15967        &mut self,
15968        snapshot: &EditorSnapshot,
15969        position: Point,
15970    ) -> Option<MultiBufferDiffHunk> {
15971        snapshot
15972            .buffer_snapshot
15973            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15974            .find(|hunk| hunk.row_range.start.0 > position.row)
15975            .or_else(|| {
15976                snapshot
15977                    .buffer_snapshot
15978                    .diff_hunks_in_range(Point::zero()..position)
15979                    .find(|hunk| hunk.row_range.end.0 < position.row)
15980            })
15981    }
15982
15983    fn go_to_prev_hunk(
15984        &mut self,
15985        _: &GoToPreviousHunk,
15986        window: &mut Window,
15987        cx: &mut Context<Self>,
15988    ) {
15989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15990        let snapshot = self.snapshot(window, cx);
15991        let selection = self.selections.newest::<Point>(cx);
15992        self.go_to_hunk_before_or_after_position(
15993            &snapshot,
15994            selection.head(),
15995            Direction::Prev,
15996            window,
15997            cx,
15998        );
15999    }
16000
16001    fn hunk_before_position(
16002        &mut self,
16003        snapshot: &EditorSnapshot,
16004        position: Point,
16005    ) -> Option<MultiBufferRow> {
16006        snapshot
16007            .buffer_snapshot
16008            .diff_hunk_before(position)
16009            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
16010    }
16011
16012    fn go_to_next_change(
16013        &mut self,
16014        _: &GoToNextChange,
16015        window: &mut Window,
16016        cx: &mut Context<Self>,
16017    ) {
16018        if let Some(selections) = self
16019            .change_list
16020            .next_change(1, Direction::Next)
16021            .map(|s| s.to_vec())
16022        {
16023            self.change_selections(Default::default(), window, cx, |s| {
16024                let map = s.display_map();
16025                s.select_display_ranges(selections.iter().map(|a| {
16026                    let point = a.to_display_point(&map);
16027                    point..point
16028                }))
16029            })
16030        }
16031    }
16032
16033    fn go_to_previous_change(
16034        &mut self,
16035        _: &GoToPreviousChange,
16036        window: &mut Window,
16037        cx: &mut Context<Self>,
16038    ) {
16039        if let Some(selections) = self
16040            .change_list
16041            .next_change(1, Direction::Prev)
16042            .map(|s| s.to_vec())
16043        {
16044            self.change_selections(Default::default(), window, cx, |s| {
16045                let map = s.display_map();
16046                s.select_display_ranges(selections.iter().map(|a| {
16047                    let point = a.to_display_point(&map);
16048                    point..point
16049                }))
16050            })
16051        }
16052    }
16053
16054    pub fn go_to_next_document_highlight(
16055        &mut self,
16056        _: &GoToNextDocumentHighlight,
16057        window: &mut Window,
16058        cx: &mut Context<Self>,
16059    ) {
16060        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16061    }
16062
16063    pub fn go_to_prev_document_highlight(
16064        &mut self,
16065        _: &GoToPreviousDocumentHighlight,
16066        window: &mut Window,
16067        cx: &mut Context<Self>,
16068    ) {
16069        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16070    }
16071
16072    pub fn go_to_document_highlight_before_or_after_position(
16073        &mut self,
16074        direction: Direction,
16075        window: &mut Window,
16076        cx: &mut Context<Editor>,
16077    ) {
16078        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16079        let snapshot = self.snapshot(window, cx);
16080        let buffer = &snapshot.buffer_snapshot;
16081        let position = self.selections.newest::<Point>(cx).head();
16082        let anchor_position = buffer.anchor_after(position);
16083
16084        // Get all document highlights (both read and write)
16085        let mut all_highlights = Vec::new();
16086
16087        if let Some((_, read_highlights)) = self
16088            .background_highlights
16089            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16090        {
16091            all_highlights.extend(read_highlights.iter());
16092        }
16093
16094        if let Some((_, write_highlights)) = self
16095            .background_highlights
16096            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16097        {
16098            all_highlights.extend(write_highlights.iter());
16099        }
16100
16101        if all_highlights.is_empty() {
16102            return;
16103        }
16104
16105        // Sort highlights by position
16106        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16107
16108        let target_highlight = match direction {
16109            Direction::Next => {
16110                // Find the first highlight after the current position
16111                all_highlights
16112                    .iter()
16113                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16114            }
16115            Direction::Prev => {
16116                // Find the last highlight before the current position
16117                all_highlights
16118                    .iter()
16119                    .rev()
16120                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16121            }
16122        };
16123
16124        if let Some(highlight) = target_highlight {
16125            let destination = highlight.start.to_point(buffer);
16126            let autoscroll = Autoscroll::center();
16127
16128            self.unfold_ranges(&[destination..destination], false, false, cx);
16129            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16130                s.select_ranges([destination..destination]);
16131            });
16132        }
16133    }
16134
16135    fn go_to_line<T: 'static>(
16136        &mut self,
16137        position: Anchor,
16138        highlight_color: Option<Hsla>,
16139        window: &mut Window,
16140        cx: &mut Context<Self>,
16141    ) {
16142        let snapshot = self.snapshot(window, cx).display_snapshot;
16143        let position = position.to_point(&snapshot.buffer_snapshot);
16144        let start = snapshot
16145            .buffer_snapshot
16146            .clip_point(Point::new(position.row, 0), Bias::Left);
16147        let end = start + Point::new(1, 0);
16148        let start = snapshot.buffer_snapshot.anchor_before(start);
16149        let end = snapshot.buffer_snapshot.anchor_before(end);
16150
16151        self.highlight_rows::<T>(
16152            start..end,
16153            highlight_color
16154                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16155            Default::default(),
16156            cx,
16157        );
16158
16159        if self.buffer.read(cx).is_singleton() {
16160            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16161        }
16162    }
16163
16164    pub fn go_to_definition(
16165        &mut self,
16166        _: &GoToDefinition,
16167        window: &mut Window,
16168        cx: &mut Context<Self>,
16169    ) -> Task<Result<Navigated>> {
16170        let definition =
16171            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16172        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16173        cx.spawn_in(window, async move |editor, cx| {
16174            if definition.await? == Navigated::Yes {
16175                return Ok(Navigated::Yes);
16176            }
16177            match fallback_strategy {
16178                GoToDefinitionFallback::None => Ok(Navigated::No),
16179                GoToDefinitionFallback::FindAllReferences => {
16180                    match editor.update_in(cx, |editor, window, cx| {
16181                        editor.find_all_references(&FindAllReferences, window, cx)
16182                    })? {
16183                        Some(references) => references.await,
16184                        None => Ok(Navigated::No),
16185                    }
16186                }
16187            }
16188        })
16189    }
16190
16191    pub fn go_to_declaration(
16192        &mut self,
16193        _: &GoToDeclaration,
16194        window: &mut Window,
16195        cx: &mut Context<Self>,
16196    ) -> Task<Result<Navigated>> {
16197        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16198    }
16199
16200    pub fn go_to_declaration_split(
16201        &mut self,
16202        _: &GoToDeclaration,
16203        window: &mut Window,
16204        cx: &mut Context<Self>,
16205    ) -> Task<Result<Navigated>> {
16206        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16207    }
16208
16209    pub fn go_to_implementation(
16210        &mut self,
16211        _: &GoToImplementation,
16212        window: &mut Window,
16213        cx: &mut Context<Self>,
16214    ) -> Task<Result<Navigated>> {
16215        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16216    }
16217
16218    pub fn go_to_implementation_split(
16219        &mut self,
16220        _: &GoToImplementationSplit,
16221        window: &mut Window,
16222        cx: &mut Context<Self>,
16223    ) -> Task<Result<Navigated>> {
16224        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16225    }
16226
16227    pub fn go_to_type_definition(
16228        &mut self,
16229        _: &GoToTypeDefinition,
16230        window: &mut Window,
16231        cx: &mut Context<Self>,
16232    ) -> Task<Result<Navigated>> {
16233        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16234    }
16235
16236    pub fn go_to_definition_split(
16237        &mut self,
16238        _: &GoToDefinitionSplit,
16239        window: &mut Window,
16240        cx: &mut Context<Self>,
16241    ) -> Task<Result<Navigated>> {
16242        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16243    }
16244
16245    pub fn go_to_type_definition_split(
16246        &mut self,
16247        _: &GoToTypeDefinitionSplit,
16248        window: &mut Window,
16249        cx: &mut Context<Self>,
16250    ) -> Task<Result<Navigated>> {
16251        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16252    }
16253
16254    fn go_to_definition_of_kind(
16255        &mut self,
16256        kind: GotoDefinitionKind,
16257        split: bool,
16258        window: &mut Window,
16259        cx: &mut Context<Self>,
16260    ) -> Task<Result<Navigated>> {
16261        let Some(provider) = self.semantics_provider.clone() else {
16262            return Task::ready(Ok(Navigated::No));
16263        };
16264        let head = self.selections.newest::<usize>(cx).head();
16265        let buffer = self.buffer.read(cx);
16266        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16267            return Task::ready(Ok(Navigated::No));
16268        };
16269        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16270            return Task::ready(Ok(Navigated::No));
16271        };
16272
16273        cx.spawn_in(window, async move |editor, cx| {
16274            let Some(definitions) = definitions.await? else {
16275                return Ok(Navigated::No);
16276            };
16277            let navigated = editor
16278                .update_in(cx, |editor, window, cx| {
16279                    editor.navigate_to_hover_links(
16280                        Some(kind),
16281                        definitions
16282                            .into_iter()
16283                            .filter(|location| {
16284                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16285                            })
16286                            .map(HoverLink::Text)
16287                            .collect::<Vec<_>>(),
16288                        split,
16289                        window,
16290                        cx,
16291                    )
16292                })?
16293                .await?;
16294            anyhow::Ok(navigated)
16295        })
16296    }
16297
16298    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16299        let selection = self.selections.newest_anchor();
16300        let head = selection.head();
16301        let tail = selection.tail();
16302
16303        let Some((buffer, start_position)) =
16304            self.buffer.read(cx).text_anchor_for_position(head, cx)
16305        else {
16306            return;
16307        };
16308
16309        let end_position = if head != tail {
16310            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16311                return;
16312            };
16313            Some(pos)
16314        } else {
16315            None
16316        };
16317
16318        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16319            let url = if let Some(end_pos) = end_position {
16320                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16321            } else {
16322                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16323            };
16324
16325            if let Some(url) = url {
16326                editor.update(cx, |_, cx| {
16327                    cx.open_url(&url);
16328                })
16329            } else {
16330                Ok(())
16331            }
16332        });
16333
16334        url_finder.detach();
16335    }
16336
16337    pub fn open_selected_filename(
16338        &mut self,
16339        _: &OpenSelectedFilename,
16340        window: &mut Window,
16341        cx: &mut Context<Self>,
16342    ) {
16343        let Some(workspace) = self.workspace() else {
16344            return;
16345        };
16346
16347        let position = self.selections.newest_anchor().head();
16348
16349        let Some((buffer, buffer_position)) =
16350            self.buffer.read(cx).text_anchor_for_position(position, cx)
16351        else {
16352            return;
16353        };
16354
16355        let project = self.project.clone();
16356
16357        cx.spawn_in(window, async move |_, cx| {
16358            let result = find_file(&buffer, project, buffer_position, cx).await;
16359
16360            if let Some((_, path)) = result {
16361                workspace
16362                    .update_in(cx, |workspace, window, cx| {
16363                        workspace.open_resolved_path(path, window, cx)
16364                    })?
16365                    .await?;
16366            }
16367            anyhow::Ok(())
16368        })
16369        .detach();
16370    }
16371
16372    pub(crate) fn navigate_to_hover_links(
16373        &mut self,
16374        kind: Option<GotoDefinitionKind>,
16375        definitions: Vec<HoverLink>,
16376        split: bool,
16377        window: &mut Window,
16378        cx: &mut Context<Editor>,
16379    ) -> Task<Result<Navigated>> {
16380        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16381        let mut first_url_or_file = None;
16382        let definitions: Vec<_> = definitions
16383            .into_iter()
16384            .filter_map(|def| match def {
16385                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16386                HoverLink::InlayHint(lsp_location, server_id) => {
16387                    let computation =
16388                        self.compute_target_location(lsp_location, server_id, window, cx);
16389                    Some(cx.background_spawn(computation))
16390                }
16391                HoverLink::Url(url) => {
16392                    first_url_or_file = Some(Either::Left(url));
16393                    None
16394                }
16395                HoverLink::File(path) => {
16396                    first_url_or_file = Some(Either::Right(path));
16397                    None
16398                }
16399            })
16400            .collect();
16401
16402        let workspace = self.workspace();
16403
16404        cx.spawn_in(window, async move |editor, acx| {
16405            let mut locations: Vec<Location> = future::join_all(definitions)
16406                .await
16407                .into_iter()
16408                .filter_map(|location| location.transpose())
16409                .collect::<Result<_>>()
16410                .context("location tasks")?;
16411
16412            if locations.len() > 1 {
16413                let Some(workspace) = workspace else {
16414                    return Ok(Navigated::No);
16415                };
16416
16417                let tab_kind = match kind {
16418                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16419                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16420                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16421                    Some(GotoDefinitionKind::Type) => "Types",
16422                };
16423                let title = editor
16424                    .update_in(acx, |_, _, cx| {
16425                        let target = locations
16426                            .iter()
16427                            .map(|location| {
16428                                location
16429                                    .buffer
16430                                    .read(cx)
16431                                    .text_for_range(location.range.clone())
16432                                    .collect::<String>()
16433                            })
16434                            .filter(|text| !text.contains('\n'))
16435                            .unique()
16436                            .take(3)
16437                            .join(", ");
16438                        if target.is_empty() {
16439                            tab_kind.to_owned()
16440                        } else {
16441                            format!("{tab_kind} for {target}")
16442                        }
16443                    })
16444                    .context("buffer title")?;
16445
16446                let opened = workspace
16447                    .update_in(acx, |workspace, window, cx| {
16448                        Self::open_locations_in_multibuffer(
16449                            workspace,
16450                            locations,
16451                            title,
16452                            split,
16453                            MultibufferSelectionMode::First,
16454                            window,
16455                            cx,
16456                        )
16457                    })
16458                    .is_ok();
16459
16460                anyhow::Ok(Navigated::from_bool(opened))
16461            } else if locations.is_empty() {
16462                // If there is one url or file, open it directly
16463                match first_url_or_file {
16464                    Some(Either::Left(url)) => {
16465                        acx.update(|_, cx| cx.open_url(&url))?;
16466                        Ok(Navigated::Yes)
16467                    }
16468                    Some(Either::Right(path)) => {
16469                        let Some(workspace) = workspace else {
16470                            return Ok(Navigated::No);
16471                        };
16472
16473                        workspace
16474                            .update_in(acx, |workspace, window, cx| {
16475                                workspace.open_resolved_path(path, window, cx)
16476                            })?
16477                            .await?;
16478                        Ok(Navigated::Yes)
16479                    }
16480                    None => Ok(Navigated::No),
16481                }
16482            } else {
16483                let Some(workspace) = workspace else {
16484                    return Ok(Navigated::No);
16485                };
16486
16487                let target = locations.pop().unwrap();
16488                editor.update_in(acx, |editor, window, cx| {
16489                    let range = target.range.to_point(target.buffer.read(cx));
16490                    let range = editor.range_for_match(&range);
16491                    let range = collapse_multiline_range(range);
16492
16493                    if !split
16494                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16495                    {
16496                        editor.go_to_singleton_buffer_range(range, window, cx);
16497                    } else {
16498                        let pane = workspace.read(cx).active_pane().clone();
16499                        window.defer(cx, move |window, cx| {
16500                            let target_editor: Entity<Self> =
16501                                workspace.update(cx, |workspace, cx| {
16502                                    let pane = if split {
16503                                        workspace.adjacent_pane(window, cx)
16504                                    } else {
16505                                        workspace.active_pane().clone()
16506                                    };
16507
16508                                    workspace.open_project_item(
16509                                        pane,
16510                                        target.buffer.clone(),
16511                                        true,
16512                                        true,
16513                                        window,
16514                                        cx,
16515                                    )
16516                                });
16517                            target_editor.update(cx, |target_editor, cx| {
16518                                // When selecting a definition in a different buffer, disable the nav history
16519                                // to avoid creating a history entry at the previous cursor location.
16520                                pane.update(cx, |pane, _| pane.disable_history());
16521                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16522                                pane.update(cx, |pane, _| pane.enable_history());
16523                            });
16524                        });
16525                    }
16526                    Navigated::Yes
16527                })
16528            }
16529        })
16530    }
16531
16532    fn compute_target_location(
16533        &self,
16534        lsp_location: lsp::Location,
16535        server_id: LanguageServerId,
16536        window: &mut Window,
16537        cx: &mut Context<Self>,
16538    ) -> Task<anyhow::Result<Option<Location>>> {
16539        let Some(project) = self.project.clone() else {
16540            return Task::ready(Ok(None));
16541        };
16542
16543        cx.spawn_in(window, async move |editor, cx| {
16544            let location_task = editor.update(cx, |_, cx| {
16545                project.update(cx, |project, cx| {
16546                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16547                })
16548            })?;
16549            let location = Some({
16550                let target_buffer_handle = location_task.await.context("open local buffer")?;
16551                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16552                    let target_start = target_buffer
16553                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16554                    let target_end = target_buffer
16555                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16556                    target_buffer.anchor_after(target_start)
16557                        ..target_buffer.anchor_before(target_end)
16558                })?;
16559                Location {
16560                    buffer: target_buffer_handle,
16561                    range,
16562                }
16563            });
16564            Ok(location)
16565        })
16566    }
16567
16568    pub fn find_all_references(
16569        &mut self,
16570        _: &FindAllReferences,
16571        window: &mut Window,
16572        cx: &mut Context<Self>,
16573    ) -> Option<Task<Result<Navigated>>> {
16574        let selection = self.selections.newest::<usize>(cx);
16575        let multi_buffer = self.buffer.read(cx);
16576        let head = selection.head();
16577
16578        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16579        let head_anchor = multi_buffer_snapshot.anchor_at(
16580            head,
16581            if head < selection.tail() {
16582                Bias::Right
16583            } else {
16584                Bias::Left
16585            },
16586        );
16587
16588        match self
16589            .find_all_references_task_sources
16590            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16591        {
16592            Ok(_) => {
16593                log::info!(
16594                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16595                );
16596                return None;
16597            }
16598            Err(i) => {
16599                self.find_all_references_task_sources.insert(i, head_anchor);
16600            }
16601        }
16602
16603        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16604        let workspace = self.workspace()?;
16605        let project = workspace.read(cx).project().clone();
16606        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16607        Some(cx.spawn_in(window, async move |editor, cx| {
16608            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16609                if let Ok(i) = editor
16610                    .find_all_references_task_sources
16611                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16612                {
16613                    editor.find_all_references_task_sources.remove(i);
16614                }
16615            });
16616
16617            let Some(locations) = references.await? else {
16618                return anyhow::Ok(Navigated::No);
16619            };
16620            if locations.is_empty() {
16621                return anyhow::Ok(Navigated::No);
16622            }
16623
16624            workspace.update_in(cx, |workspace, window, cx| {
16625                let target = locations
16626                    .iter()
16627                    .map(|location| {
16628                        location
16629                            .buffer
16630                            .read(cx)
16631                            .text_for_range(location.range.clone())
16632                            .collect::<String>()
16633                    })
16634                    .filter(|text| !text.contains('\n'))
16635                    .unique()
16636                    .take(3)
16637                    .join(", ");
16638                let title = if target.is_empty() {
16639                    "References".to_owned()
16640                } else {
16641                    format!("References to {target}")
16642                };
16643                Self::open_locations_in_multibuffer(
16644                    workspace,
16645                    locations,
16646                    title,
16647                    false,
16648                    MultibufferSelectionMode::First,
16649                    window,
16650                    cx,
16651                );
16652                Navigated::Yes
16653            })
16654        }))
16655    }
16656
16657    /// Opens a multibuffer with the given project locations in it
16658    pub fn open_locations_in_multibuffer(
16659        workspace: &mut Workspace,
16660        mut locations: Vec<Location>,
16661        title: String,
16662        split: bool,
16663        multibuffer_selection_mode: MultibufferSelectionMode,
16664        window: &mut Window,
16665        cx: &mut Context<Workspace>,
16666    ) {
16667        if locations.is_empty() {
16668            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16669            return;
16670        }
16671
16672        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16673
16674        let mut locations = locations.into_iter().peekable();
16675        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16676        let capability = workspace.project().read(cx).capability();
16677
16678        // a key to find existing multibuffer editors with the same set of locations
16679        // to prevent us from opening more and more multibuffer tabs for searches and the like
16680        let mut key = (title.clone(), vec![]);
16681        let excerpt_buffer = cx.new(|cx| {
16682            let key = &mut key.1;
16683            let mut multibuffer = MultiBuffer::new(capability);
16684            while let Some(location) = locations.next() {
16685                let buffer = location.buffer.read(cx);
16686                let mut ranges_for_buffer = Vec::new();
16687                let range = location.range.to_point(buffer);
16688                ranges_for_buffer.push(range.clone());
16689
16690                while let Some(next_location) =
16691                    locations.next_if(|next_location| next_location.buffer == location.buffer)
16692                {
16693                    ranges_for_buffer.push(next_location.range.to_point(buffer));
16694                }
16695
16696                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16697                key.push((
16698                    location.buffer.read(cx).remote_id(),
16699                    ranges_for_buffer.clone(),
16700                ));
16701                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16702                    PathKey::for_buffer(&location.buffer, cx),
16703                    location.buffer.clone(),
16704                    ranges_for_buffer,
16705                    multibuffer_context_lines(cx),
16706                    cx,
16707                );
16708                ranges.extend(new_ranges)
16709            }
16710
16711            multibuffer.with_title(title)
16712        });
16713        let existing = workspace.active_pane().update(cx, |pane, cx| {
16714            pane.items()
16715                .filter_map(|item| item.downcast::<Editor>())
16716                .find(|editor| {
16717                    editor
16718                        .read(cx)
16719                        .lookup_key
16720                        .as_ref()
16721                        .and_then(|it| {
16722                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16723                        })
16724                        .is_some_and(|it| *it == key)
16725                })
16726        });
16727        let editor = existing.unwrap_or_else(|| {
16728            cx.new(|cx| {
16729                let mut editor = Editor::for_multibuffer(
16730                    excerpt_buffer,
16731                    Some(workspace.project().clone()),
16732                    window,
16733                    cx,
16734                );
16735                editor.lookup_key = Some(Box::new(key));
16736                editor
16737            })
16738        });
16739        editor.update(cx, |editor, cx| {
16740            match multibuffer_selection_mode {
16741                MultibufferSelectionMode::First => {
16742                    if let Some(first_range) = ranges.first() {
16743                        editor.change_selections(
16744                            SelectionEffects::no_scroll(),
16745                            window,
16746                            cx,
16747                            |selections| {
16748                                selections.clear_disjoint();
16749                                selections
16750                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16751                            },
16752                        );
16753                    }
16754                    editor.highlight_background::<Self>(
16755                        &ranges,
16756                        |theme| theme.colors().editor_highlighted_line_background,
16757                        cx,
16758                    );
16759                }
16760                MultibufferSelectionMode::All => {
16761                    editor.change_selections(
16762                        SelectionEffects::no_scroll(),
16763                        window,
16764                        cx,
16765                        |selections| {
16766                            selections.clear_disjoint();
16767                            selections.select_anchor_ranges(ranges);
16768                        },
16769                    );
16770                }
16771            }
16772            editor.register_buffers_with_language_servers(cx);
16773        });
16774
16775        let item = Box::new(editor);
16776        let item_id = item.item_id();
16777
16778        if split {
16779            workspace.split_item(SplitDirection::Right, item, window, cx);
16780        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16781            let (preview_item_id, preview_item_idx) =
16782                workspace.active_pane().read_with(cx, |pane, _| {
16783                    (pane.preview_item_id(), pane.preview_item_idx())
16784                });
16785
16786            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16787
16788            if let Some(preview_item_id) = preview_item_id {
16789                workspace.active_pane().update(cx, |pane, cx| {
16790                    pane.remove_item(preview_item_id, false, false, window, cx);
16791                });
16792            }
16793        } else {
16794            workspace.add_item_to_active_pane(item, None, true, window, cx);
16795        }
16796        workspace.active_pane().update(cx, |pane, cx| {
16797            pane.set_preview_item_id(Some(item_id), cx);
16798        });
16799    }
16800
16801    pub fn rename(
16802        &mut self,
16803        _: &Rename,
16804        window: &mut Window,
16805        cx: &mut Context<Self>,
16806    ) -> Option<Task<Result<()>>> {
16807        use language::ToOffset as _;
16808
16809        let provider = self.semantics_provider.clone()?;
16810        let selection = self.selections.newest_anchor().clone();
16811        let (cursor_buffer, cursor_buffer_position) = self
16812            .buffer
16813            .read(cx)
16814            .text_anchor_for_position(selection.head(), cx)?;
16815        let (tail_buffer, cursor_buffer_position_end) = self
16816            .buffer
16817            .read(cx)
16818            .text_anchor_for_position(selection.tail(), cx)?;
16819        if tail_buffer != cursor_buffer {
16820            return None;
16821        }
16822
16823        let snapshot = cursor_buffer.read(cx).snapshot();
16824        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16825        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16826        let prepare_rename = provider
16827            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16828            .unwrap_or_else(|| Task::ready(Ok(None)));
16829        drop(snapshot);
16830
16831        Some(cx.spawn_in(window, async move |this, cx| {
16832            let rename_range = if let Some(range) = prepare_rename.await? {
16833                Some(range)
16834            } else {
16835                this.update(cx, |this, cx| {
16836                    let buffer = this.buffer.read(cx).snapshot(cx);
16837                    let mut buffer_highlights = this
16838                        .document_highlights_for_position(selection.head(), &buffer)
16839                        .filter(|highlight| {
16840                            highlight.start.excerpt_id == selection.head().excerpt_id
16841                                && highlight.end.excerpt_id == selection.head().excerpt_id
16842                        });
16843                    buffer_highlights
16844                        .next()
16845                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16846                })?
16847            };
16848            if let Some(rename_range) = rename_range {
16849                this.update_in(cx, |this, window, cx| {
16850                    let snapshot = cursor_buffer.read(cx).snapshot();
16851                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16852                    let cursor_offset_in_rename_range =
16853                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16854                    let cursor_offset_in_rename_range_end =
16855                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16856
16857                    this.take_rename(false, window, cx);
16858                    let buffer = this.buffer.read(cx).read(cx);
16859                    let cursor_offset = selection.head().to_offset(&buffer);
16860                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16861                    let rename_end = rename_start + rename_buffer_range.len();
16862                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16863                    let mut old_highlight_id = None;
16864                    let old_name: Arc<str> = buffer
16865                        .chunks(rename_start..rename_end, true)
16866                        .map(|chunk| {
16867                            if old_highlight_id.is_none() {
16868                                old_highlight_id = chunk.syntax_highlight_id;
16869                            }
16870                            chunk.text
16871                        })
16872                        .collect::<String>()
16873                        .into();
16874
16875                    drop(buffer);
16876
16877                    // Position the selection in the rename editor so that it matches the current selection.
16878                    this.show_local_selections = false;
16879                    let rename_editor = cx.new(|cx| {
16880                        let mut editor = Editor::single_line(window, cx);
16881                        editor.buffer.update(cx, |buffer, cx| {
16882                            buffer.edit([(0..0, old_name.clone())], None, cx)
16883                        });
16884                        let rename_selection_range = match cursor_offset_in_rename_range
16885                            .cmp(&cursor_offset_in_rename_range_end)
16886                        {
16887                            Ordering::Equal => {
16888                                editor.select_all(&SelectAll, window, cx);
16889                                return editor;
16890                            }
16891                            Ordering::Less => {
16892                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16893                            }
16894                            Ordering::Greater => {
16895                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16896                            }
16897                        };
16898                        if rename_selection_range.end > old_name.len() {
16899                            editor.select_all(&SelectAll, window, cx);
16900                        } else {
16901                            editor.change_selections(Default::default(), window, cx, |s| {
16902                                s.select_ranges([rename_selection_range]);
16903                            });
16904                        }
16905                        editor
16906                    });
16907                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16908                        if e == &EditorEvent::Focused {
16909                            cx.emit(EditorEvent::FocusedIn)
16910                        }
16911                    })
16912                    .detach();
16913
16914                    let write_highlights =
16915                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16916                    let read_highlights =
16917                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16918                    let ranges = write_highlights
16919                        .iter()
16920                        .flat_map(|(_, ranges)| ranges.iter())
16921                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16922                        .cloned()
16923                        .collect();
16924
16925                    this.highlight_text::<Rename>(
16926                        ranges,
16927                        HighlightStyle {
16928                            fade_out: Some(0.6),
16929                            ..Default::default()
16930                        },
16931                        cx,
16932                    );
16933                    let rename_focus_handle = rename_editor.focus_handle(cx);
16934                    window.focus(&rename_focus_handle);
16935                    let block_id = this.insert_blocks(
16936                        [BlockProperties {
16937                            style: BlockStyle::Flex,
16938                            placement: BlockPlacement::Below(range.start),
16939                            height: Some(1),
16940                            render: Arc::new({
16941                                let rename_editor = rename_editor.clone();
16942                                move |cx: &mut BlockContext| {
16943                                    let mut text_style = cx.editor_style.text.clone();
16944                                    if let Some(highlight_style) = old_highlight_id
16945                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16946                                    {
16947                                        text_style = text_style.highlight(highlight_style);
16948                                    }
16949                                    div()
16950                                        .block_mouse_except_scroll()
16951                                        .pl(cx.anchor_x)
16952                                        .child(EditorElement::new(
16953                                            &rename_editor,
16954                                            EditorStyle {
16955                                                background: cx.theme().system().transparent,
16956                                                local_player: cx.editor_style.local_player,
16957                                                text: text_style,
16958                                                scrollbar_width: cx.editor_style.scrollbar_width,
16959                                                syntax: cx.editor_style.syntax.clone(),
16960                                                status: cx.editor_style.status.clone(),
16961                                                inlay_hints_style: HighlightStyle {
16962                                                    font_weight: Some(FontWeight::BOLD),
16963                                                    ..make_inlay_hints_style(cx.app)
16964                                                },
16965                                                edit_prediction_styles: make_suggestion_styles(
16966                                                    cx.app,
16967                                                ),
16968                                                ..EditorStyle::default()
16969                                            },
16970                                        ))
16971                                        .into_any_element()
16972                                }
16973                            }),
16974                            priority: 0,
16975                        }],
16976                        Some(Autoscroll::fit()),
16977                        cx,
16978                    )[0];
16979                    this.pending_rename = Some(RenameState {
16980                        range,
16981                        old_name,
16982                        editor: rename_editor,
16983                        block_id,
16984                    });
16985                })?;
16986            }
16987
16988            Ok(())
16989        }))
16990    }
16991
16992    pub fn confirm_rename(
16993        &mut self,
16994        _: &ConfirmRename,
16995        window: &mut Window,
16996        cx: &mut Context<Self>,
16997    ) -> Option<Task<Result<()>>> {
16998        let rename = self.take_rename(false, window, cx)?;
16999        let workspace = self.workspace()?.downgrade();
17000        let (buffer, start) = self
17001            .buffer
17002            .read(cx)
17003            .text_anchor_for_position(rename.range.start, cx)?;
17004        let (end_buffer, _) = self
17005            .buffer
17006            .read(cx)
17007            .text_anchor_for_position(rename.range.end, cx)?;
17008        if buffer != end_buffer {
17009            return None;
17010        }
17011
17012        let old_name = rename.old_name;
17013        let new_name = rename.editor.read(cx).text(cx);
17014
17015        let rename = self.semantics_provider.as_ref()?.perform_rename(
17016            &buffer,
17017            start,
17018            new_name.clone(),
17019            cx,
17020        )?;
17021
17022        Some(cx.spawn_in(window, async move |editor, cx| {
17023            let project_transaction = rename.await?;
17024            Self::open_project_transaction(
17025                &editor,
17026                workspace,
17027                project_transaction,
17028                format!("Rename: {}{}", old_name, new_name),
17029                cx,
17030            )
17031            .await?;
17032
17033            editor.update(cx, |editor, cx| {
17034                editor.refresh_document_highlights(cx);
17035            })?;
17036            Ok(())
17037        }))
17038    }
17039
17040    fn take_rename(
17041        &mut self,
17042        moving_cursor: bool,
17043        window: &mut Window,
17044        cx: &mut Context<Self>,
17045    ) -> Option<RenameState> {
17046        let rename = self.pending_rename.take()?;
17047        if rename.editor.focus_handle(cx).is_focused(window) {
17048            window.focus(&self.focus_handle);
17049        }
17050
17051        self.remove_blocks(
17052            [rename.block_id].into_iter().collect(),
17053            Some(Autoscroll::fit()),
17054            cx,
17055        );
17056        self.clear_highlights::<Rename>(cx);
17057        self.show_local_selections = true;
17058
17059        if moving_cursor {
17060            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17061                editor.selections.newest::<usize>(cx).head()
17062            });
17063
17064            // Update the selection to match the position of the selection inside
17065            // the rename editor.
17066            let snapshot = self.buffer.read(cx).read(cx);
17067            let rename_range = rename.range.to_offset(&snapshot);
17068            let cursor_in_editor = snapshot
17069                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17070                .min(rename_range.end);
17071            drop(snapshot);
17072
17073            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17074                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17075            });
17076        } else {
17077            self.refresh_document_highlights(cx);
17078        }
17079
17080        Some(rename)
17081    }
17082
17083    pub fn pending_rename(&self) -> Option<&RenameState> {
17084        self.pending_rename.as_ref()
17085    }
17086
17087    fn format(
17088        &mut self,
17089        _: &Format,
17090        window: &mut Window,
17091        cx: &mut Context<Self>,
17092    ) -> Option<Task<Result<()>>> {
17093        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17094
17095        let project = match &self.project {
17096            Some(project) => project.clone(),
17097            None => return None,
17098        };
17099
17100        Some(self.perform_format(
17101            project,
17102            FormatTrigger::Manual,
17103            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17104            window,
17105            cx,
17106        ))
17107    }
17108
17109    fn format_selections(
17110        &mut self,
17111        _: &FormatSelections,
17112        window: &mut Window,
17113        cx: &mut Context<Self>,
17114    ) -> Option<Task<Result<()>>> {
17115        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17116
17117        let project = match &self.project {
17118            Some(project) => project.clone(),
17119            None => return None,
17120        };
17121
17122        let ranges = self
17123            .selections
17124            .all_adjusted(cx)
17125            .into_iter()
17126            .map(|selection| selection.range())
17127            .collect_vec();
17128
17129        Some(self.perform_format(
17130            project,
17131            FormatTrigger::Manual,
17132            FormatTarget::Ranges(ranges),
17133            window,
17134            cx,
17135        ))
17136    }
17137
17138    fn perform_format(
17139        &mut self,
17140        project: Entity<Project>,
17141        trigger: FormatTrigger,
17142        target: FormatTarget,
17143        window: &mut Window,
17144        cx: &mut Context<Self>,
17145    ) -> Task<Result<()>> {
17146        let buffer = self.buffer.clone();
17147        let (buffers, target) = match target {
17148            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17149            FormatTarget::Ranges(selection_ranges) => {
17150                let multi_buffer = buffer.read(cx);
17151                let snapshot = multi_buffer.read(cx);
17152                let mut buffers = HashSet::default();
17153                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17154                    BTreeMap::new();
17155                for selection_range in selection_ranges {
17156                    for (buffer, buffer_range, _) in
17157                        snapshot.range_to_buffer_ranges(selection_range)
17158                    {
17159                        let buffer_id = buffer.remote_id();
17160                        let start = buffer.anchor_before(buffer_range.start);
17161                        let end = buffer.anchor_after(buffer_range.end);
17162                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17163                        buffer_id_to_ranges
17164                            .entry(buffer_id)
17165                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17166                            .or_insert_with(|| vec![start..end]);
17167                    }
17168                }
17169                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17170            }
17171        };
17172
17173        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17174        let selections_prev = transaction_id_prev
17175            .and_then(|transaction_id_prev| {
17176                // default to selections as they were after the last edit, if we have them,
17177                // instead of how they are now.
17178                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17179                // will take you back to where you made the last edit, instead of staying where you scrolled
17180                self.selection_history
17181                    .transaction(transaction_id_prev)
17182                    .map(|t| t.0.clone())
17183            })
17184            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17185
17186        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17187        let format = project.update(cx, |project, cx| {
17188            project.format(buffers, target, true, trigger, cx)
17189        });
17190
17191        cx.spawn_in(window, async move |editor, cx| {
17192            let transaction = futures::select_biased! {
17193                transaction = format.log_err().fuse() => transaction,
17194                () = timeout => {
17195                    log::warn!("timed out waiting for formatting");
17196                    None
17197                }
17198            };
17199
17200            buffer
17201                .update(cx, |buffer, cx| {
17202                    if let Some(transaction) = transaction
17203                        && !buffer.is_singleton()
17204                    {
17205                        buffer.push_transaction(&transaction.0, cx);
17206                    }
17207                    cx.notify();
17208                })
17209                .ok();
17210
17211            if let Some(transaction_id_now) =
17212                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17213            {
17214                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17215                if has_new_transaction {
17216                    _ = editor.update(cx, |editor, _| {
17217                        editor
17218                            .selection_history
17219                            .insert_transaction(transaction_id_now, selections_prev);
17220                    });
17221                }
17222            }
17223
17224            Ok(())
17225        })
17226    }
17227
17228    fn organize_imports(
17229        &mut self,
17230        _: &OrganizeImports,
17231        window: &mut Window,
17232        cx: &mut Context<Self>,
17233    ) -> Option<Task<Result<()>>> {
17234        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17235        let project = match &self.project {
17236            Some(project) => project.clone(),
17237            None => return None,
17238        };
17239        Some(self.perform_code_action_kind(
17240            project,
17241            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17242            window,
17243            cx,
17244        ))
17245    }
17246
17247    fn perform_code_action_kind(
17248        &mut self,
17249        project: Entity<Project>,
17250        kind: CodeActionKind,
17251        window: &mut Window,
17252        cx: &mut Context<Self>,
17253    ) -> Task<Result<()>> {
17254        let buffer = self.buffer.clone();
17255        let buffers = buffer.read(cx).all_buffers();
17256        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17257        let apply_action = project.update(cx, |project, cx| {
17258            project.apply_code_action_kind(buffers, kind, true, cx)
17259        });
17260        cx.spawn_in(window, async move |_, cx| {
17261            let transaction = futures::select_biased! {
17262                () = timeout => {
17263                    log::warn!("timed out waiting for executing code action");
17264                    None
17265                }
17266                transaction = apply_action.log_err().fuse() => transaction,
17267            };
17268            buffer
17269                .update(cx, |buffer, cx| {
17270                    // check if we need this
17271                    if let Some(transaction) = transaction
17272                        && !buffer.is_singleton()
17273                    {
17274                        buffer.push_transaction(&transaction.0, cx);
17275                    }
17276                    cx.notify();
17277                })
17278                .ok();
17279            Ok(())
17280        })
17281    }
17282
17283    pub fn restart_language_server(
17284        &mut self,
17285        _: &RestartLanguageServer,
17286        _: &mut Window,
17287        cx: &mut Context<Self>,
17288    ) {
17289        if let Some(project) = self.project.clone() {
17290            self.buffer.update(cx, |multi_buffer, cx| {
17291                project.update(cx, |project, cx| {
17292                    project.restart_language_servers_for_buffers(
17293                        multi_buffer.all_buffers().into_iter().collect(),
17294                        HashSet::default(),
17295                        cx,
17296                    );
17297                });
17298            })
17299        }
17300    }
17301
17302    pub fn stop_language_server(
17303        &mut self,
17304        _: &StopLanguageServer,
17305        _: &mut Window,
17306        cx: &mut Context<Self>,
17307    ) {
17308        if let Some(project) = self.project.clone() {
17309            self.buffer.update(cx, |multi_buffer, cx| {
17310                project.update(cx, |project, cx| {
17311                    project.stop_language_servers_for_buffers(
17312                        multi_buffer.all_buffers().into_iter().collect(),
17313                        HashSet::default(),
17314                        cx,
17315                    );
17316                    cx.emit(project::Event::RefreshInlayHints);
17317                });
17318            });
17319        }
17320    }
17321
17322    fn cancel_language_server_work(
17323        workspace: &mut Workspace,
17324        _: &actions::CancelLanguageServerWork,
17325        _: &mut Window,
17326        cx: &mut Context<Workspace>,
17327    ) {
17328        let project = workspace.project();
17329        let buffers = workspace
17330            .active_item(cx)
17331            .and_then(|item| item.act_as::<Editor>(cx))
17332            .map_or(HashSet::default(), |editor| {
17333                editor.read(cx).buffer.read(cx).all_buffers()
17334            });
17335        project.update(cx, |project, cx| {
17336            project.cancel_language_server_work_for_buffers(buffers, cx);
17337        });
17338    }
17339
17340    fn show_character_palette(
17341        &mut self,
17342        _: &ShowCharacterPalette,
17343        window: &mut Window,
17344        _: &mut Context<Self>,
17345    ) {
17346        window.show_character_palette();
17347    }
17348
17349    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17350        if !self.diagnostics_enabled() {
17351            return;
17352        }
17353
17354        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17355            let buffer = self.buffer.read(cx).snapshot(cx);
17356            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17357            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17358            let is_valid = buffer
17359                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17360                .any(|entry| {
17361                    entry.diagnostic.is_primary
17362                        && !entry.range.is_empty()
17363                        && entry.range.start == primary_range_start
17364                        && entry.diagnostic.message == active_diagnostics.active_message
17365                });
17366
17367            if !is_valid {
17368                self.dismiss_diagnostics(cx);
17369            }
17370        }
17371    }
17372
17373    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17374        match &self.active_diagnostics {
17375            ActiveDiagnostic::Group(group) => Some(group),
17376            _ => None,
17377        }
17378    }
17379
17380    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17381        if !self.diagnostics_enabled() {
17382            return;
17383        }
17384        self.dismiss_diagnostics(cx);
17385        self.active_diagnostics = ActiveDiagnostic::All;
17386    }
17387
17388    fn activate_diagnostics(
17389        &mut self,
17390        buffer_id: BufferId,
17391        diagnostic: DiagnosticEntry<usize>,
17392        window: &mut Window,
17393        cx: &mut Context<Self>,
17394    ) {
17395        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17396            return;
17397        }
17398        self.dismiss_diagnostics(cx);
17399        let snapshot = self.snapshot(window, cx);
17400        let buffer = self.buffer.read(cx).snapshot(cx);
17401        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17402            return;
17403        };
17404
17405        let diagnostic_group = buffer
17406            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17407            .collect::<Vec<_>>();
17408
17409        let blocks =
17410            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17411
17412        let blocks = self.display_map.update(cx, |display_map, cx| {
17413            display_map.insert_blocks(blocks, cx).into_iter().collect()
17414        });
17415        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17416            active_range: buffer.anchor_before(diagnostic.range.start)
17417                ..buffer.anchor_after(diagnostic.range.end),
17418            active_message: diagnostic.diagnostic.message.clone(),
17419            group_id: diagnostic.diagnostic.group_id,
17420            blocks,
17421        });
17422        cx.notify();
17423    }
17424
17425    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17426        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17427            return;
17428        };
17429
17430        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17431        if let ActiveDiagnostic::Group(group) = prev {
17432            self.display_map.update(cx, |display_map, cx| {
17433                display_map.remove_blocks(group.blocks, cx);
17434            });
17435            cx.notify();
17436        }
17437    }
17438
17439    /// Disable inline diagnostics rendering for this editor.
17440    pub fn disable_inline_diagnostics(&mut self) {
17441        self.inline_diagnostics_enabled = false;
17442        self.inline_diagnostics_update = Task::ready(());
17443        self.inline_diagnostics.clear();
17444    }
17445
17446    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17447        self.diagnostics_enabled = false;
17448        self.dismiss_diagnostics(cx);
17449        self.inline_diagnostics_update = Task::ready(());
17450        self.inline_diagnostics.clear();
17451    }
17452
17453    pub fn disable_word_completions(&mut self) {
17454        self.word_completions_enabled = false;
17455    }
17456
17457    pub fn diagnostics_enabled(&self) -> bool {
17458        self.diagnostics_enabled && self.mode.is_full()
17459    }
17460
17461    pub fn inline_diagnostics_enabled(&self) -> bool {
17462        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17463    }
17464
17465    pub fn show_inline_diagnostics(&self) -> bool {
17466        self.show_inline_diagnostics
17467    }
17468
17469    pub fn toggle_inline_diagnostics(
17470        &mut self,
17471        _: &ToggleInlineDiagnostics,
17472        window: &mut Window,
17473        cx: &mut Context<Editor>,
17474    ) {
17475        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17476        self.refresh_inline_diagnostics(false, window, cx);
17477    }
17478
17479    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17480        self.diagnostics_max_severity = severity;
17481        self.display_map.update(cx, |display_map, _| {
17482            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17483        });
17484    }
17485
17486    pub fn toggle_diagnostics(
17487        &mut self,
17488        _: &ToggleDiagnostics,
17489        window: &mut Window,
17490        cx: &mut Context<Editor>,
17491    ) {
17492        if !self.diagnostics_enabled() {
17493            return;
17494        }
17495
17496        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17497            EditorSettings::get_global(cx)
17498                .diagnostics_max_severity
17499                .filter(|severity| severity != &DiagnosticSeverity::Off)
17500                .unwrap_or(DiagnosticSeverity::Hint)
17501        } else {
17502            DiagnosticSeverity::Off
17503        };
17504        self.set_max_diagnostics_severity(new_severity, cx);
17505        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17506            self.active_diagnostics = ActiveDiagnostic::None;
17507            self.inline_diagnostics_update = Task::ready(());
17508            self.inline_diagnostics.clear();
17509        } else {
17510            self.refresh_inline_diagnostics(false, window, cx);
17511        }
17512
17513        cx.notify();
17514    }
17515
17516    pub fn toggle_minimap(
17517        &mut self,
17518        _: &ToggleMinimap,
17519        window: &mut Window,
17520        cx: &mut Context<Editor>,
17521    ) {
17522        if self.supports_minimap(cx) {
17523            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17524        }
17525    }
17526
17527    fn refresh_inline_diagnostics(
17528        &mut self,
17529        debounce: bool,
17530        window: &mut Window,
17531        cx: &mut Context<Self>,
17532    ) {
17533        let max_severity = ProjectSettings::get_global(cx)
17534            .diagnostics
17535            .inline
17536            .max_severity
17537            .unwrap_or(self.diagnostics_max_severity);
17538
17539        if !self.inline_diagnostics_enabled()
17540            || !self.show_inline_diagnostics
17541            || max_severity == DiagnosticSeverity::Off
17542        {
17543            self.inline_diagnostics_update = Task::ready(());
17544            self.inline_diagnostics.clear();
17545            return;
17546        }
17547
17548        let debounce_ms = ProjectSettings::get_global(cx)
17549            .diagnostics
17550            .inline
17551            .update_debounce_ms;
17552        let debounce = if debounce && debounce_ms > 0 {
17553            Some(Duration::from_millis(debounce_ms))
17554        } else {
17555            None
17556        };
17557        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17558            if let Some(debounce) = debounce {
17559                cx.background_executor().timer(debounce).await;
17560            }
17561            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17562                editor
17563                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17564                    .ok()
17565            }) else {
17566                return;
17567            };
17568
17569            let new_inline_diagnostics = cx
17570                .background_spawn(async move {
17571                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17572                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17573                        let message = diagnostic_entry
17574                            .diagnostic
17575                            .message
17576                            .split_once('\n')
17577                            .map(|(line, _)| line)
17578                            .map(SharedString::new)
17579                            .unwrap_or_else(|| {
17580                                SharedString::from(diagnostic_entry.diagnostic.message)
17581                            });
17582                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17583                        let (Ok(i) | Err(i)) = inline_diagnostics
17584                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17585                        inline_diagnostics.insert(
17586                            i,
17587                            (
17588                                start_anchor,
17589                                InlineDiagnostic {
17590                                    message,
17591                                    group_id: diagnostic_entry.diagnostic.group_id,
17592                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17593                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17594                                    severity: diagnostic_entry.diagnostic.severity,
17595                                },
17596                            ),
17597                        );
17598                    }
17599                    inline_diagnostics
17600                })
17601                .await;
17602
17603            editor
17604                .update(cx, |editor, cx| {
17605                    editor.inline_diagnostics = new_inline_diagnostics;
17606                    cx.notify();
17607                })
17608                .ok();
17609        });
17610    }
17611
17612    fn pull_diagnostics(
17613        &mut self,
17614        buffer_id: Option<BufferId>,
17615        window: &Window,
17616        cx: &mut Context<Self>,
17617    ) -> Option<()> {
17618        if !self.mode().is_full() {
17619            return None;
17620        }
17621        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17622            .diagnostics
17623            .lsp_pull_diagnostics;
17624        if !pull_diagnostics_settings.enabled {
17625            return None;
17626        }
17627        let project = self.project()?.downgrade();
17628        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17629        let mut buffers = self.buffer.read(cx).all_buffers();
17630        if let Some(buffer_id) = buffer_id {
17631            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17632        }
17633
17634        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17635            cx.background_executor().timer(debounce).await;
17636
17637            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17638                buffers
17639                    .into_iter()
17640                    .filter_map(|buffer| {
17641                        project
17642                            .update(cx, |project, cx| {
17643                                project.lsp_store().update(cx, |lsp_store, cx| {
17644                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17645                                })
17646                            })
17647                            .ok()
17648                    })
17649                    .collect::<FuturesUnordered<_>>()
17650            }) else {
17651                return;
17652            };
17653
17654            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17655                match pull_task {
17656                    Ok(()) => {
17657                        if editor
17658                            .update_in(cx, |editor, window, cx| {
17659                                editor.update_diagnostics_state(window, cx);
17660                            })
17661                            .is_err()
17662                        {
17663                            return;
17664                        }
17665                    }
17666                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17667                }
17668            }
17669        });
17670
17671        Some(())
17672    }
17673
17674    pub fn set_selections_from_remote(
17675        &mut self,
17676        selections: Vec<Selection<Anchor>>,
17677        pending_selection: Option<Selection<Anchor>>,
17678        window: &mut Window,
17679        cx: &mut Context<Self>,
17680    ) {
17681        let old_cursor_position = self.selections.newest_anchor().head();
17682        self.selections.change_with(cx, |s| {
17683            s.select_anchors(selections);
17684            if let Some(pending_selection) = pending_selection {
17685                s.set_pending(pending_selection, SelectMode::Character);
17686            } else {
17687                s.clear_pending();
17688            }
17689        });
17690        self.selections_did_change(
17691            false,
17692            &old_cursor_position,
17693            SelectionEffects::default(),
17694            window,
17695            cx,
17696        );
17697    }
17698
17699    pub fn transact(
17700        &mut self,
17701        window: &mut Window,
17702        cx: &mut Context<Self>,
17703        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17704    ) -> Option<TransactionId> {
17705        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17706            this.start_transaction_at(Instant::now(), window, cx);
17707            update(this, window, cx);
17708            this.end_transaction_at(Instant::now(), cx)
17709        })
17710    }
17711
17712    pub fn start_transaction_at(
17713        &mut self,
17714        now: Instant,
17715        window: &mut Window,
17716        cx: &mut Context<Self>,
17717    ) -> Option<TransactionId> {
17718        self.end_selection(window, cx);
17719        if let Some(tx_id) = self
17720            .buffer
17721            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17722        {
17723            self.selection_history
17724                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
17725            cx.emit(EditorEvent::TransactionBegun {
17726                transaction_id: tx_id,
17727            });
17728            Some(tx_id)
17729        } else {
17730            None
17731        }
17732    }
17733
17734    pub fn end_transaction_at(
17735        &mut self,
17736        now: Instant,
17737        cx: &mut Context<Self>,
17738    ) -> Option<TransactionId> {
17739        if let Some(transaction_id) = self
17740            .buffer
17741            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17742        {
17743            if let Some((_, end_selections)) =
17744                self.selection_history.transaction_mut(transaction_id)
17745            {
17746                *end_selections = Some(self.selections.disjoint_anchors_arc());
17747            } else {
17748                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17749            }
17750
17751            cx.emit(EditorEvent::Edited { transaction_id });
17752            Some(transaction_id)
17753        } else {
17754            None
17755        }
17756    }
17757
17758    pub fn modify_transaction_selection_history(
17759        &mut self,
17760        transaction_id: TransactionId,
17761        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17762    ) -> bool {
17763        self.selection_history
17764            .transaction_mut(transaction_id)
17765            .map(modify)
17766            .is_some()
17767    }
17768
17769    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17770        if self.selection_mark_mode {
17771            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17772                s.move_with(|_, sel| {
17773                    sel.collapse_to(sel.head(), SelectionGoal::None);
17774                });
17775            })
17776        }
17777        self.selection_mark_mode = true;
17778        cx.notify();
17779    }
17780
17781    pub fn swap_selection_ends(
17782        &mut self,
17783        _: &actions::SwapSelectionEnds,
17784        window: &mut Window,
17785        cx: &mut Context<Self>,
17786    ) {
17787        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17788            s.move_with(|_, sel| {
17789                if sel.start != sel.end {
17790                    sel.reversed = !sel.reversed
17791                }
17792            });
17793        });
17794        self.request_autoscroll(Autoscroll::newest(), cx);
17795        cx.notify();
17796    }
17797
17798    pub fn toggle_focus(
17799        workspace: &mut Workspace,
17800        _: &actions::ToggleFocus,
17801        window: &mut Window,
17802        cx: &mut Context<Workspace>,
17803    ) {
17804        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17805            return;
17806        };
17807        workspace.activate_item(&item, true, true, window, cx);
17808    }
17809
17810    pub fn toggle_fold(
17811        &mut self,
17812        _: &actions::ToggleFold,
17813        window: &mut Window,
17814        cx: &mut Context<Self>,
17815    ) {
17816        if self.is_singleton(cx) {
17817            let selection = self.selections.newest::<Point>(cx);
17818
17819            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17820            let range = if selection.is_empty() {
17821                let point = selection.head().to_display_point(&display_map);
17822                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17823                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17824                    .to_point(&display_map);
17825                start..end
17826            } else {
17827                selection.range()
17828            };
17829            if display_map.folds_in_range(range).next().is_some() {
17830                self.unfold_lines(&Default::default(), window, cx)
17831            } else {
17832                self.fold(&Default::default(), window, cx)
17833            }
17834        } else {
17835            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17836            let buffer_ids: HashSet<_> = self
17837                .selections
17838                .disjoint_anchor_ranges()
17839                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17840                .collect();
17841
17842            let should_unfold = buffer_ids
17843                .iter()
17844                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17845
17846            for buffer_id in buffer_ids {
17847                if should_unfold {
17848                    self.unfold_buffer(buffer_id, cx);
17849                } else {
17850                    self.fold_buffer(buffer_id, cx);
17851                }
17852            }
17853        }
17854    }
17855
17856    pub fn toggle_fold_recursive(
17857        &mut self,
17858        _: &actions::ToggleFoldRecursive,
17859        window: &mut Window,
17860        cx: &mut Context<Self>,
17861    ) {
17862        let selection = self.selections.newest::<Point>(cx);
17863
17864        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17865        let range = if selection.is_empty() {
17866            let point = selection.head().to_display_point(&display_map);
17867            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17868            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17869                .to_point(&display_map);
17870            start..end
17871        } else {
17872            selection.range()
17873        };
17874        if display_map.folds_in_range(range).next().is_some() {
17875            self.unfold_recursive(&Default::default(), window, cx)
17876        } else {
17877            self.fold_recursive(&Default::default(), window, cx)
17878        }
17879    }
17880
17881    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17882        if self.is_singleton(cx) {
17883            let mut to_fold = Vec::new();
17884            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17885            let selections = self.selections.all_adjusted(cx);
17886
17887            for selection in selections {
17888                let range = selection.range().sorted();
17889                let buffer_start_row = range.start.row;
17890
17891                if range.start.row != range.end.row {
17892                    let mut found = false;
17893                    let mut row = range.start.row;
17894                    while row <= range.end.row {
17895                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17896                        {
17897                            found = true;
17898                            row = crease.range().end.row + 1;
17899                            to_fold.push(crease);
17900                        } else {
17901                            row += 1
17902                        }
17903                    }
17904                    if found {
17905                        continue;
17906                    }
17907                }
17908
17909                for row in (0..=range.start.row).rev() {
17910                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17911                        && crease.range().end.row >= buffer_start_row
17912                    {
17913                        to_fold.push(crease);
17914                        if row <= range.start.row {
17915                            break;
17916                        }
17917                    }
17918                }
17919            }
17920
17921            self.fold_creases(to_fold, true, window, cx);
17922        } else {
17923            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17924            let buffer_ids = self
17925                .selections
17926                .disjoint_anchor_ranges()
17927                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17928                .collect::<HashSet<_>>();
17929            for buffer_id in buffer_ids {
17930                self.fold_buffer(buffer_id, cx);
17931            }
17932        }
17933    }
17934
17935    pub fn toggle_fold_all(
17936        &mut self,
17937        _: &actions::ToggleFoldAll,
17938        window: &mut Window,
17939        cx: &mut Context<Self>,
17940    ) {
17941        if self.buffer.read(cx).is_singleton() {
17942            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17943            let has_folds = display_map
17944                .folds_in_range(0..display_map.buffer_snapshot.len())
17945                .next()
17946                .is_some();
17947
17948            if has_folds {
17949                self.unfold_all(&actions::UnfoldAll, window, cx);
17950            } else {
17951                self.fold_all(&actions::FoldAll, window, cx);
17952            }
17953        } else {
17954            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17955            let should_unfold = buffer_ids
17956                .iter()
17957                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17958
17959            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17960                editor
17961                    .update_in(cx, |editor, _, cx| {
17962                        for buffer_id in buffer_ids {
17963                            if should_unfold {
17964                                editor.unfold_buffer(buffer_id, cx);
17965                            } else {
17966                                editor.fold_buffer(buffer_id, cx);
17967                            }
17968                        }
17969                    })
17970                    .ok();
17971            });
17972        }
17973    }
17974
17975    fn fold_at_level(
17976        &mut self,
17977        fold_at: &FoldAtLevel,
17978        window: &mut Window,
17979        cx: &mut Context<Self>,
17980    ) {
17981        if !self.buffer.read(cx).is_singleton() {
17982            return;
17983        }
17984
17985        let fold_at_level = fold_at.0;
17986        let snapshot = self.buffer.read(cx).snapshot(cx);
17987        let mut to_fold = Vec::new();
17988        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17989
17990        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17991            while start_row < end_row {
17992                match self
17993                    .snapshot(window, cx)
17994                    .crease_for_buffer_row(MultiBufferRow(start_row))
17995                {
17996                    Some(crease) => {
17997                        let nested_start_row = crease.range().start.row + 1;
17998                        let nested_end_row = crease.range().end.row;
17999
18000                        if current_level < fold_at_level {
18001                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18002                        } else if current_level == fold_at_level {
18003                            to_fold.push(crease);
18004                        }
18005
18006                        start_row = nested_end_row + 1;
18007                    }
18008                    None => start_row += 1,
18009                }
18010            }
18011        }
18012
18013        self.fold_creases(to_fold, true, window, cx);
18014    }
18015
18016    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18017        if self.buffer.read(cx).is_singleton() {
18018            let mut fold_ranges = Vec::new();
18019            let snapshot = self.buffer.read(cx).snapshot(cx);
18020
18021            for row in 0..snapshot.max_row().0 {
18022                if let Some(foldable_range) = self
18023                    .snapshot(window, cx)
18024                    .crease_for_buffer_row(MultiBufferRow(row))
18025                {
18026                    fold_ranges.push(foldable_range);
18027                }
18028            }
18029
18030            self.fold_creases(fold_ranges, true, window, cx);
18031        } else {
18032            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18033                editor
18034                    .update_in(cx, |editor, _, cx| {
18035                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18036                            editor.fold_buffer(buffer_id, cx);
18037                        }
18038                    })
18039                    .ok();
18040            });
18041        }
18042    }
18043
18044    pub fn fold_function_bodies(
18045        &mut self,
18046        _: &actions::FoldFunctionBodies,
18047        window: &mut Window,
18048        cx: &mut Context<Self>,
18049    ) {
18050        let snapshot = self.buffer.read(cx).snapshot(cx);
18051
18052        let ranges = snapshot
18053            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18054            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18055            .collect::<Vec<_>>();
18056
18057        let creases = ranges
18058            .into_iter()
18059            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18060            .collect();
18061
18062        self.fold_creases(creases, true, window, cx);
18063    }
18064
18065    pub fn fold_recursive(
18066        &mut self,
18067        _: &actions::FoldRecursive,
18068        window: &mut Window,
18069        cx: &mut Context<Self>,
18070    ) {
18071        let mut to_fold = Vec::new();
18072        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18073        let selections = self.selections.all_adjusted(cx);
18074
18075        for selection in selections {
18076            let range = selection.range().sorted();
18077            let buffer_start_row = range.start.row;
18078
18079            if range.start.row != range.end.row {
18080                let mut found = false;
18081                for row in range.start.row..=range.end.row {
18082                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18083                        found = true;
18084                        to_fold.push(crease);
18085                    }
18086                }
18087                if found {
18088                    continue;
18089                }
18090            }
18091
18092            for row in (0..=range.start.row).rev() {
18093                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18094                    if crease.range().end.row >= buffer_start_row {
18095                        to_fold.push(crease);
18096                    } else {
18097                        break;
18098                    }
18099                }
18100            }
18101        }
18102
18103        self.fold_creases(to_fold, true, window, cx);
18104    }
18105
18106    pub fn fold_at(
18107        &mut self,
18108        buffer_row: MultiBufferRow,
18109        window: &mut Window,
18110        cx: &mut Context<Self>,
18111    ) {
18112        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18113
18114        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18115            let autoscroll = self
18116                .selections
18117                .all::<Point>(cx)
18118                .iter()
18119                .any(|selection| crease.range().overlaps(&selection.range()));
18120
18121            self.fold_creases(vec![crease], autoscroll, window, cx);
18122        }
18123    }
18124
18125    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18126        if self.is_singleton(cx) {
18127            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18128            let buffer = &display_map.buffer_snapshot;
18129            let selections = self.selections.all::<Point>(cx);
18130            let ranges = selections
18131                .iter()
18132                .map(|s| {
18133                    let range = s.display_range(&display_map).sorted();
18134                    let mut start = range.start.to_point(&display_map);
18135                    let mut end = range.end.to_point(&display_map);
18136                    start.column = 0;
18137                    end.column = buffer.line_len(MultiBufferRow(end.row));
18138                    start..end
18139                })
18140                .collect::<Vec<_>>();
18141
18142            self.unfold_ranges(&ranges, true, true, cx);
18143        } else {
18144            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18145            let buffer_ids = self
18146                .selections
18147                .disjoint_anchor_ranges()
18148                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18149                .collect::<HashSet<_>>();
18150            for buffer_id in buffer_ids {
18151                self.unfold_buffer(buffer_id, cx);
18152            }
18153        }
18154    }
18155
18156    pub fn unfold_recursive(
18157        &mut self,
18158        _: &UnfoldRecursive,
18159        _window: &mut Window,
18160        cx: &mut Context<Self>,
18161    ) {
18162        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18163        let selections = self.selections.all::<Point>(cx);
18164        let ranges = selections
18165            .iter()
18166            .map(|s| {
18167                let mut range = s.display_range(&display_map).sorted();
18168                *range.start.column_mut() = 0;
18169                *range.end.column_mut() = display_map.line_len(range.end.row());
18170                let start = range.start.to_point(&display_map);
18171                let end = range.end.to_point(&display_map);
18172                start..end
18173            })
18174            .collect::<Vec<_>>();
18175
18176        self.unfold_ranges(&ranges, true, true, cx);
18177    }
18178
18179    pub fn unfold_at(
18180        &mut self,
18181        buffer_row: MultiBufferRow,
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
18187        let intersection_range = Point::new(buffer_row.0, 0)
18188            ..Point::new(
18189                buffer_row.0,
18190                display_map.buffer_snapshot.line_len(buffer_row),
18191            );
18192
18193        let autoscroll = self
18194            .selections
18195            .all::<Point>(cx)
18196            .iter()
18197            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18198
18199        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18200    }
18201
18202    pub fn unfold_all(
18203        &mut self,
18204        _: &actions::UnfoldAll,
18205        _window: &mut Window,
18206        cx: &mut Context<Self>,
18207    ) {
18208        if self.buffer.read(cx).is_singleton() {
18209            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18210            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18211        } else {
18212            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18213                editor
18214                    .update(cx, |editor, cx| {
18215                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18216                            editor.unfold_buffer(buffer_id, cx);
18217                        }
18218                    })
18219                    .ok();
18220            });
18221        }
18222    }
18223
18224    pub fn fold_selected_ranges(
18225        &mut self,
18226        _: &FoldSelectedRanges,
18227        window: &mut Window,
18228        cx: &mut Context<Self>,
18229    ) {
18230        let selections = self.selections.all_adjusted(cx);
18231        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18232        let ranges = selections
18233            .into_iter()
18234            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18235            .collect::<Vec<_>>();
18236        self.fold_creases(ranges, true, window, cx);
18237    }
18238
18239    pub fn fold_ranges<T: ToOffset + Clone>(
18240        &mut self,
18241        ranges: Vec<Range<T>>,
18242        auto_scroll: bool,
18243        window: &mut Window,
18244        cx: &mut Context<Self>,
18245    ) {
18246        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18247        let ranges = ranges
18248            .into_iter()
18249            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18250            .collect::<Vec<_>>();
18251        self.fold_creases(ranges, auto_scroll, window, cx);
18252    }
18253
18254    pub fn fold_creases<T: ToOffset + Clone>(
18255        &mut self,
18256        creases: Vec<Crease<T>>,
18257        auto_scroll: bool,
18258        _window: &mut Window,
18259        cx: &mut Context<Self>,
18260    ) {
18261        if creases.is_empty() {
18262            return;
18263        }
18264
18265        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18266
18267        if auto_scroll {
18268            self.request_autoscroll(Autoscroll::fit(), cx);
18269        }
18270
18271        cx.notify();
18272
18273        self.scrollbar_marker_state.dirty = true;
18274        self.folds_did_change(cx);
18275    }
18276
18277    /// Removes any folds whose ranges intersect any of the given ranges.
18278    pub fn unfold_ranges<T: ToOffset + Clone>(
18279        &mut self,
18280        ranges: &[Range<T>],
18281        inclusive: bool,
18282        auto_scroll: bool,
18283        cx: &mut Context<Self>,
18284    ) {
18285        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18286            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18287        });
18288        self.folds_did_change(cx);
18289    }
18290
18291    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18292        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18293            return;
18294        }
18295        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18296        self.display_map.update(cx, |display_map, cx| {
18297            display_map.fold_buffers([buffer_id], cx)
18298        });
18299        cx.emit(EditorEvent::BufferFoldToggled {
18300            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18301            folded: true,
18302        });
18303        cx.notify();
18304    }
18305
18306    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18307        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18308            return;
18309        }
18310        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18311        self.display_map.update(cx, |display_map, cx| {
18312            display_map.unfold_buffers([buffer_id], cx);
18313        });
18314        cx.emit(EditorEvent::BufferFoldToggled {
18315            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18316            folded: false,
18317        });
18318        cx.notify();
18319    }
18320
18321    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18322        self.display_map.read(cx).is_buffer_folded(buffer)
18323    }
18324
18325    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18326        self.display_map.read(cx).folded_buffers()
18327    }
18328
18329    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18330        self.display_map.update(cx, |display_map, cx| {
18331            display_map.disable_header_for_buffer(buffer_id, cx);
18332        });
18333        cx.notify();
18334    }
18335
18336    /// Removes any folds with the given ranges.
18337    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18338        &mut self,
18339        ranges: &[Range<T>],
18340        type_id: TypeId,
18341        auto_scroll: bool,
18342        cx: &mut Context<Self>,
18343    ) {
18344        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18345            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18346        });
18347        self.folds_did_change(cx);
18348    }
18349
18350    fn remove_folds_with<T: ToOffset + Clone>(
18351        &mut self,
18352        ranges: &[Range<T>],
18353        auto_scroll: bool,
18354        cx: &mut Context<Self>,
18355        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18356    ) {
18357        if ranges.is_empty() {
18358            return;
18359        }
18360
18361        let mut buffers_affected = HashSet::default();
18362        let multi_buffer = self.buffer().read(cx);
18363        for range in ranges {
18364            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18365                buffers_affected.insert(buffer.read(cx).remote_id());
18366            };
18367        }
18368
18369        self.display_map.update(cx, update);
18370
18371        if auto_scroll {
18372            self.request_autoscroll(Autoscroll::fit(), cx);
18373        }
18374
18375        cx.notify();
18376        self.scrollbar_marker_state.dirty = true;
18377        self.active_indent_guides_state.dirty = true;
18378    }
18379
18380    pub fn update_renderer_widths(
18381        &mut self,
18382        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18383        cx: &mut Context<Self>,
18384    ) -> bool {
18385        self.display_map
18386            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18387    }
18388
18389    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18390        self.display_map.read(cx).fold_placeholder.clone()
18391    }
18392
18393    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18394        self.buffer.update(cx, |buffer, cx| {
18395            buffer.set_all_diff_hunks_expanded(cx);
18396        });
18397    }
18398
18399    pub fn expand_all_diff_hunks(
18400        &mut self,
18401        _: &ExpandAllDiffHunks,
18402        _window: &mut Window,
18403        cx: &mut Context<Self>,
18404    ) {
18405        self.buffer.update(cx, |buffer, cx| {
18406            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18407        });
18408    }
18409
18410    pub fn toggle_selected_diff_hunks(
18411        &mut self,
18412        _: &ToggleSelectedDiffHunks,
18413        _window: &mut Window,
18414        cx: &mut Context<Self>,
18415    ) {
18416        let ranges: Vec<_> = self
18417            .selections
18418            .disjoint_anchors()
18419            .iter()
18420            .map(|s| s.range())
18421            .collect();
18422        self.toggle_diff_hunks_in_ranges(ranges, cx);
18423    }
18424
18425    pub fn diff_hunks_in_ranges<'a>(
18426        &'a self,
18427        ranges: &'a [Range<Anchor>],
18428        buffer: &'a MultiBufferSnapshot,
18429    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18430        ranges.iter().flat_map(move |range| {
18431            let end_excerpt_id = range.end.excerpt_id;
18432            let range = range.to_point(buffer);
18433            let mut peek_end = range.end;
18434            if range.end.row < buffer.max_row().0 {
18435                peek_end = Point::new(range.end.row + 1, 0);
18436            }
18437            buffer
18438                .diff_hunks_in_range(range.start..peek_end)
18439                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18440        })
18441    }
18442
18443    pub fn has_stageable_diff_hunks_in_ranges(
18444        &self,
18445        ranges: &[Range<Anchor>],
18446        snapshot: &MultiBufferSnapshot,
18447    ) -> bool {
18448        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18449        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18450    }
18451
18452    pub fn toggle_staged_selected_diff_hunks(
18453        &mut self,
18454        _: &::git::ToggleStaged,
18455        _: &mut Window,
18456        cx: &mut Context<Self>,
18457    ) {
18458        let snapshot = self.buffer.read(cx).snapshot(cx);
18459        let ranges: Vec<_> = self
18460            .selections
18461            .disjoint_anchors()
18462            .iter()
18463            .map(|s| s.range())
18464            .collect();
18465        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18466        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18467    }
18468
18469    pub fn set_render_diff_hunk_controls(
18470        &mut self,
18471        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18472        cx: &mut Context<Self>,
18473    ) {
18474        self.render_diff_hunk_controls = render_diff_hunk_controls;
18475        cx.notify();
18476    }
18477
18478    pub fn stage_and_next(
18479        &mut self,
18480        _: &::git::StageAndNext,
18481        window: &mut Window,
18482        cx: &mut Context<Self>,
18483    ) {
18484        self.do_stage_or_unstage_and_next(true, window, cx);
18485    }
18486
18487    pub fn unstage_and_next(
18488        &mut self,
18489        _: &::git::UnstageAndNext,
18490        window: &mut Window,
18491        cx: &mut Context<Self>,
18492    ) {
18493        self.do_stage_or_unstage_and_next(false, window, cx);
18494    }
18495
18496    pub fn stage_or_unstage_diff_hunks(
18497        &mut self,
18498        stage: bool,
18499        ranges: Vec<Range<Anchor>>,
18500        cx: &mut Context<Self>,
18501    ) {
18502        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18503        cx.spawn(async move |this, cx| {
18504            task.await?;
18505            this.update(cx, |this, cx| {
18506                let snapshot = this.buffer.read(cx).snapshot(cx);
18507                let chunk_by = this
18508                    .diff_hunks_in_ranges(&ranges, &snapshot)
18509                    .chunk_by(|hunk| hunk.buffer_id);
18510                for (buffer_id, hunks) in &chunk_by {
18511                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18512                }
18513            })
18514        })
18515        .detach_and_log_err(cx);
18516    }
18517
18518    fn save_buffers_for_ranges_if_needed(
18519        &mut self,
18520        ranges: &[Range<Anchor>],
18521        cx: &mut Context<Editor>,
18522    ) -> Task<Result<()>> {
18523        let multibuffer = self.buffer.read(cx);
18524        let snapshot = multibuffer.read(cx);
18525        let buffer_ids: HashSet<_> = ranges
18526            .iter()
18527            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18528            .collect();
18529        drop(snapshot);
18530
18531        let mut buffers = HashSet::default();
18532        for buffer_id in buffer_ids {
18533            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18534                let buffer = buffer_entity.read(cx);
18535                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18536                {
18537                    buffers.insert(buffer_entity);
18538                }
18539            }
18540        }
18541
18542        if let Some(project) = &self.project {
18543            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18544        } else {
18545            Task::ready(Ok(()))
18546        }
18547    }
18548
18549    fn do_stage_or_unstage_and_next(
18550        &mut self,
18551        stage: bool,
18552        window: &mut Window,
18553        cx: &mut Context<Self>,
18554    ) {
18555        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18556
18557        if ranges.iter().any(|range| range.start != range.end) {
18558            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18559            return;
18560        }
18561
18562        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18563        let snapshot = self.snapshot(window, cx);
18564        let position = self.selections.newest::<Point>(cx).head();
18565        let mut row = snapshot
18566            .buffer_snapshot
18567            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18568            .find(|hunk| hunk.row_range.start.0 > position.row)
18569            .map(|hunk| hunk.row_range.start);
18570
18571        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18572        // Outside of the project diff editor, wrap around to the beginning.
18573        if !all_diff_hunks_expanded {
18574            row = row.or_else(|| {
18575                snapshot
18576                    .buffer_snapshot
18577                    .diff_hunks_in_range(Point::zero()..position)
18578                    .find(|hunk| hunk.row_range.end.0 < position.row)
18579                    .map(|hunk| hunk.row_range.start)
18580            });
18581        }
18582
18583        if let Some(row) = row {
18584            let destination = Point::new(row.0, 0);
18585            let autoscroll = Autoscroll::center();
18586
18587            self.unfold_ranges(&[destination..destination], false, false, cx);
18588            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18589                s.select_ranges([destination..destination]);
18590            });
18591        }
18592    }
18593
18594    fn do_stage_or_unstage(
18595        &self,
18596        stage: bool,
18597        buffer_id: BufferId,
18598        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18599        cx: &mut App,
18600    ) -> Option<()> {
18601        let project = self.project()?;
18602        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18603        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18604        let buffer_snapshot = buffer.read(cx).snapshot();
18605        let file_exists = buffer_snapshot
18606            .file()
18607            .is_some_and(|file| file.disk_state().exists());
18608        diff.update(cx, |diff, cx| {
18609            diff.stage_or_unstage_hunks(
18610                stage,
18611                &hunks
18612                    .map(|hunk| buffer_diff::DiffHunk {
18613                        buffer_range: hunk.buffer_range,
18614                        diff_base_byte_range: hunk.diff_base_byte_range,
18615                        secondary_status: hunk.secondary_status,
18616                        range: Point::zero()..Point::zero(), // unused
18617                    })
18618                    .collect::<Vec<_>>(),
18619                &buffer_snapshot,
18620                file_exists,
18621                cx,
18622            )
18623        });
18624        None
18625    }
18626
18627    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18628        let ranges: Vec<_> = self
18629            .selections
18630            .disjoint_anchors()
18631            .iter()
18632            .map(|s| s.range())
18633            .collect();
18634        self.buffer
18635            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18636    }
18637
18638    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18639        self.buffer.update(cx, |buffer, cx| {
18640            let ranges = vec![Anchor::min()..Anchor::max()];
18641            if !buffer.all_diff_hunks_expanded()
18642                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18643            {
18644                buffer.collapse_diff_hunks(ranges, cx);
18645                true
18646            } else {
18647                false
18648            }
18649        })
18650    }
18651
18652    fn toggle_diff_hunks_in_ranges(
18653        &mut self,
18654        ranges: Vec<Range<Anchor>>,
18655        cx: &mut Context<Editor>,
18656    ) {
18657        self.buffer.update(cx, |buffer, cx| {
18658            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18659            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18660        })
18661    }
18662
18663    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18664        self.buffer.update(cx, |buffer, cx| {
18665            let snapshot = buffer.snapshot(cx);
18666            let excerpt_id = range.end.excerpt_id;
18667            let point_range = range.to_point(&snapshot);
18668            let expand = !buffer.single_hunk_is_expanded(range, cx);
18669            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18670        })
18671    }
18672
18673    pub(crate) fn apply_all_diff_hunks(
18674        &mut self,
18675        _: &ApplyAllDiffHunks,
18676        window: &mut Window,
18677        cx: &mut Context<Self>,
18678    ) {
18679        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18680
18681        let buffers = self.buffer.read(cx).all_buffers();
18682        for branch_buffer in buffers {
18683            branch_buffer.update(cx, |branch_buffer, cx| {
18684                branch_buffer.merge_into_base(Vec::new(), cx);
18685            });
18686        }
18687
18688        if let Some(project) = self.project.clone() {
18689            self.save(
18690                SaveOptions {
18691                    format: true,
18692                    autosave: false,
18693                },
18694                project,
18695                window,
18696                cx,
18697            )
18698            .detach_and_log_err(cx);
18699        }
18700    }
18701
18702    pub(crate) fn apply_selected_diff_hunks(
18703        &mut self,
18704        _: &ApplyDiffHunk,
18705        window: &mut Window,
18706        cx: &mut Context<Self>,
18707    ) {
18708        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18709        let snapshot = self.snapshot(window, cx);
18710        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18711        let mut ranges_by_buffer = HashMap::default();
18712        self.transact(window, cx, |editor, _window, cx| {
18713            for hunk in hunks {
18714                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18715                    ranges_by_buffer
18716                        .entry(buffer.clone())
18717                        .or_insert_with(Vec::new)
18718                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18719                }
18720            }
18721
18722            for (buffer, ranges) in ranges_by_buffer {
18723                buffer.update(cx, |buffer, cx| {
18724                    buffer.merge_into_base(ranges, cx);
18725                });
18726            }
18727        });
18728
18729        if let Some(project) = self.project.clone() {
18730            self.save(
18731                SaveOptions {
18732                    format: true,
18733                    autosave: false,
18734                },
18735                project,
18736                window,
18737                cx,
18738            )
18739            .detach_and_log_err(cx);
18740        }
18741    }
18742
18743    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18744        if hovered != self.gutter_hovered {
18745            self.gutter_hovered = hovered;
18746            cx.notify();
18747        }
18748    }
18749
18750    pub fn insert_blocks(
18751        &mut self,
18752        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18753        autoscroll: Option<Autoscroll>,
18754        cx: &mut Context<Self>,
18755    ) -> Vec<CustomBlockId> {
18756        let blocks = self
18757            .display_map
18758            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18759        if let Some(autoscroll) = autoscroll {
18760            self.request_autoscroll(autoscroll, cx);
18761        }
18762        cx.notify();
18763        blocks
18764    }
18765
18766    pub fn resize_blocks(
18767        &mut self,
18768        heights: HashMap<CustomBlockId, u32>,
18769        autoscroll: Option<Autoscroll>,
18770        cx: &mut Context<Self>,
18771    ) {
18772        self.display_map
18773            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18774        if let Some(autoscroll) = autoscroll {
18775            self.request_autoscroll(autoscroll, cx);
18776        }
18777        cx.notify();
18778    }
18779
18780    pub fn replace_blocks(
18781        &mut self,
18782        renderers: HashMap<CustomBlockId, RenderBlock>,
18783        autoscroll: Option<Autoscroll>,
18784        cx: &mut Context<Self>,
18785    ) {
18786        self.display_map
18787            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18788        if let Some(autoscroll) = autoscroll {
18789            self.request_autoscroll(autoscroll, cx);
18790        }
18791        cx.notify();
18792    }
18793
18794    pub fn remove_blocks(
18795        &mut self,
18796        block_ids: HashSet<CustomBlockId>,
18797        autoscroll: Option<Autoscroll>,
18798        cx: &mut Context<Self>,
18799    ) {
18800        self.display_map.update(cx, |display_map, cx| {
18801            display_map.remove_blocks(block_ids, cx)
18802        });
18803        if let Some(autoscroll) = autoscroll {
18804            self.request_autoscroll(autoscroll, cx);
18805        }
18806        cx.notify();
18807    }
18808
18809    pub fn row_for_block(
18810        &self,
18811        block_id: CustomBlockId,
18812        cx: &mut Context<Self>,
18813    ) -> Option<DisplayRow> {
18814        self.display_map
18815            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18816    }
18817
18818    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18819        self.focused_block = Some(focused_block);
18820    }
18821
18822    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18823        self.focused_block.take()
18824    }
18825
18826    pub fn insert_creases(
18827        &mut self,
18828        creases: impl IntoIterator<Item = Crease<Anchor>>,
18829        cx: &mut Context<Self>,
18830    ) -> Vec<CreaseId> {
18831        self.display_map
18832            .update(cx, |map, cx| map.insert_creases(creases, cx))
18833    }
18834
18835    pub fn remove_creases(
18836        &mut self,
18837        ids: impl IntoIterator<Item = CreaseId>,
18838        cx: &mut Context<Self>,
18839    ) -> Vec<(CreaseId, Range<Anchor>)> {
18840        self.display_map
18841            .update(cx, |map, cx| map.remove_creases(ids, cx))
18842    }
18843
18844    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18845        self.display_map
18846            .update(cx, |map, cx| map.snapshot(cx))
18847            .longest_row()
18848    }
18849
18850    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18851        self.display_map
18852            .update(cx, |map, cx| map.snapshot(cx))
18853            .max_point()
18854    }
18855
18856    pub fn text(&self, cx: &App) -> String {
18857        self.buffer.read(cx).read(cx).text()
18858    }
18859
18860    pub fn is_empty(&self, cx: &App) -> bool {
18861        self.buffer.read(cx).read(cx).is_empty()
18862    }
18863
18864    pub fn text_option(&self, cx: &App) -> Option<String> {
18865        let text = self.text(cx);
18866        let text = text.trim();
18867
18868        if text.is_empty() {
18869            return None;
18870        }
18871
18872        Some(text.to_string())
18873    }
18874
18875    pub fn set_text(
18876        &mut self,
18877        text: impl Into<Arc<str>>,
18878        window: &mut Window,
18879        cx: &mut Context<Self>,
18880    ) {
18881        self.transact(window, cx, |this, _, cx| {
18882            this.buffer
18883                .read(cx)
18884                .as_singleton()
18885                .expect("you can only call set_text on editors for singleton buffers")
18886                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18887        });
18888    }
18889
18890    pub fn display_text(&self, cx: &mut App) -> String {
18891        self.display_map
18892            .update(cx, |map, cx| map.snapshot(cx))
18893            .text()
18894    }
18895
18896    fn create_minimap(
18897        &self,
18898        minimap_settings: MinimapSettings,
18899        window: &mut Window,
18900        cx: &mut Context<Self>,
18901    ) -> Option<Entity<Self>> {
18902        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18903            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18904    }
18905
18906    fn initialize_new_minimap(
18907        &self,
18908        minimap_settings: MinimapSettings,
18909        window: &mut Window,
18910        cx: &mut Context<Self>,
18911    ) -> Entity<Self> {
18912        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18913
18914        let mut minimap = Editor::new_internal(
18915            EditorMode::Minimap {
18916                parent: cx.weak_entity(),
18917            },
18918            self.buffer.clone(),
18919            None,
18920            Some(self.display_map.clone()),
18921            window,
18922            cx,
18923        );
18924        minimap.scroll_manager.clone_state(&self.scroll_manager);
18925        minimap.set_text_style_refinement(TextStyleRefinement {
18926            font_size: Some(MINIMAP_FONT_SIZE),
18927            font_weight: Some(MINIMAP_FONT_WEIGHT),
18928            ..Default::default()
18929        });
18930        minimap.update_minimap_configuration(minimap_settings, cx);
18931        cx.new(|_| minimap)
18932    }
18933
18934    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18935        let current_line_highlight = minimap_settings
18936            .current_line_highlight
18937            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18938        self.set_current_line_highlight(Some(current_line_highlight));
18939    }
18940
18941    pub fn minimap(&self) -> Option<&Entity<Self>> {
18942        self.minimap
18943            .as_ref()
18944            .filter(|_| self.minimap_visibility.visible())
18945    }
18946
18947    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18948        let mut wrap_guides = smallvec![];
18949
18950        if self.show_wrap_guides == Some(false) {
18951            return wrap_guides;
18952        }
18953
18954        let settings = self.buffer.read(cx).language_settings(cx);
18955        if settings.show_wrap_guides {
18956            match self.soft_wrap_mode(cx) {
18957                SoftWrap::Column(soft_wrap) => {
18958                    wrap_guides.push((soft_wrap as usize, true));
18959                }
18960                SoftWrap::Bounded(soft_wrap) => {
18961                    wrap_guides.push((soft_wrap as usize, true));
18962                }
18963                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18964            }
18965            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18966        }
18967
18968        wrap_guides
18969    }
18970
18971    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18972        let settings = self.buffer.read(cx).language_settings(cx);
18973        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18974        match mode {
18975            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18976                SoftWrap::None
18977            }
18978            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18979            language_settings::SoftWrap::PreferredLineLength => {
18980                SoftWrap::Column(settings.preferred_line_length)
18981            }
18982            language_settings::SoftWrap::Bounded => {
18983                SoftWrap::Bounded(settings.preferred_line_length)
18984            }
18985        }
18986    }
18987
18988    pub fn set_soft_wrap_mode(
18989        &mut self,
18990        mode: language_settings::SoftWrap,
18991
18992        cx: &mut Context<Self>,
18993    ) {
18994        self.soft_wrap_mode_override = Some(mode);
18995        cx.notify();
18996    }
18997
18998    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18999        self.hard_wrap = hard_wrap;
19000        cx.notify();
19001    }
19002
19003    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19004        self.text_style_refinement = Some(style);
19005    }
19006
19007    /// called by the Element so we know what style we were most recently rendered with.
19008    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19009        // We intentionally do not inform the display map about the minimap style
19010        // so that wrapping is not recalculated and stays consistent for the editor
19011        // and its linked minimap.
19012        if !self.mode.is_minimap() {
19013            let font = style.text.font();
19014            let font_size = style.text.font_size.to_pixels(window.rem_size());
19015            let display_map = self
19016                .placeholder_display_map
19017                .as_ref()
19018                .filter(|_| self.is_empty(cx))
19019                .unwrap_or(&self.display_map);
19020
19021            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19022        }
19023        self.style = Some(style);
19024    }
19025
19026    pub fn style(&self) -> Option<&EditorStyle> {
19027        self.style.as_ref()
19028    }
19029
19030    // Called by the element. This method is not designed to be called outside of the editor
19031    // element's layout code because it does not notify when rewrapping is computed synchronously.
19032    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19033        if self.is_empty(cx) {
19034            self.placeholder_display_map
19035                .as_ref()
19036                .map_or(false, |display_map| {
19037                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19038                })
19039        } else {
19040            self.display_map
19041                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19042        }
19043    }
19044
19045    pub fn set_soft_wrap(&mut self) {
19046        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19047    }
19048
19049    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19050        if self.soft_wrap_mode_override.is_some() {
19051            self.soft_wrap_mode_override.take();
19052        } else {
19053            let soft_wrap = match self.soft_wrap_mode(cx) {
19054                SoftWrap::GitDiff => return,
19055                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19056                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19057                    language_settings::SoftWrap::None
19058                }
19059            };
19060            self.soft_wrap_mode_override = Some(soft_wrap);
19061        }
19062        cx.notify();
19063    }
19064
19065    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19066        let Some(workspace) = self.workspace() else {
19067            return;
19068        };
19069        let fs = workspace.read(cx).app_state().fs.clone();
19070        let current_show = TabBarSettings::get_global(cx).show;
19071        update_settings_file(fs, cx, move |setting, _| {
19072            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19073        });
19074    }
19075
19076    pub fn toggle_indent_guides(
19077        &mut self,
19078        _: &ToggleIndentGuides,
19079        _: &mut Window,
19080        cx: &mut Context<Self>,
19081    ) {
19082        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19083            self.buffer
19084                .read(cx)
19085                .language_settings(cx)
19086                .indent_guides
19087                .enabled
19088        });
19089        self.show_indent_guides = Some(!currently_enabled);
19090        cx.notify();
19091    }
19092
19093    fn should_show_indent_guides(&self) -> Option<bool> {
19094        self.show_indent_guides
19095    }
19096
19097    pub fn toggle_line_numbers(
19098        &mut self,
19099        _: &ToggleLineNumbers,
19100        _: &mut Window,
19101        cx: &mut Context<Self>,
19102    ) {
19103        let mut editor_settings = EditorSettings::get_global(cx).clone();
19104        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19105        EditorSettings::override_global(editor_settings, cx);
19106    }
19107
19108    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19109        if let Some(show_line_numbers) = self.show_line_numbers {
19110            return show_line_numbers;
19111        }
19112        EditorSettings::get_global(cx).gutter.line_numbers
19113    }
19114
19115    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19116        self.use_relative_line_numbers
19117            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19118    }
19119
19120    pub fn toggle_relative_line_numbers(
19121        &mut self,
19122        _: &ToggleRelativeLineNumbers,
19123        _: &mut Window,
19124        cx: &mut Context<Self>,
19125    ) {
19126        let is_relative = self.should_use_relative_line_numbers(cx);
19127        self.set_relative_line_number(Some(!is_relative), cx)
19128    }
19129
19130    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19131        self.use_relative_line_numbers = is_relative;
19132        cx.notify();
19133    }
19134
19135    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19136        self.show_gutter = show_gutter;
19137        cx.notify();
19138    }
19139
19140    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19141        self.show_scrollbars = ScrollbarAxes {
19142            horizontal: show,
19143            vertical: show,
19144        };
19145        cx.notify();
19146    }
19147
19148    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19149        self.show_scrollbars.vertical = show;
19150        cx.notify();
19151    }
19152
19153    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19154        self.show_scrollbars.horizontal = show;
19155        cx.notify();
19156    }
19157
19158    pub fn set_minimap_visibility(
19159        &mut self,
19160        minimap_visibility: MinimapVisibility,
19161        window: &mut Window,
19162        cx: &mut Context<Self>,
19163    ) {
19164        if self.minimap_visibility != minimap_visibility {
19165            if minimap_visibility.visible() && self.minimap.is_none() {
19166                let minimap_settings = EditorSettings::get_global(cx).minimap;
19167                self.minimap =
19168                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19169            }
19170            self.minimap_visibility = minimap_visibility;
19171            cx.notify();
19172        }
19173    }
19174
19175    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19176        self.set_show_scrollbars(false, cx);
19177        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19178    }
19179
19180    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19181        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19182    }
19183
19184    /// Normally the text in full mode and auto height editors is padded on the
19185    /// left side by roughly half a character width for improved hit testing.
19186    ///
19187    /// Use this method to disable this for cases where this is not wanted (e.g.
19188    /// if you want to align the editor text with some other text above or below)
19189    /// or if you want to add this padding to single-line editors.
19190    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19191        self.offset_content = offset_content;
19192        cx.notify();
19193    }
19194
19195    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19196        self.show_line_numbers = Some(show_line_numbers);
19197        cx.notify();
19198    }
19199
19200    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19201        self.disable_expand_excerpt_buttons = true;
19202        cx.notify();
19203    }
19204
19205    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19206        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19207        cx.notify();
19208    }
19209
19210    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19211        self.show_code_actions = Some(show_code_actions);
19212        cx.notify();
19213    }
19214
19215    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19216        self.show_runnables = Some(show_runnables);
19217        cx.notify();
19218    }
19219
19220    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19221        self.show_breakpoints = Some(show_breakpoints);
19222        cx.notify();
19223    }
19224
19225    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19226        if self.display_map.read(cx).masked != masked {
19227            self.display_map.update(cx, |map, _| map.masked = masked);
19228        }
19229        cx.notify()
19230    }
19231
19232    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19233        self.show_wrap_guides = Some(show_wrap_guides);
19234        cx.notify();
19235    }
19236
19237    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19238        self.show_indent_guides = Some(show_indent_guides);
19239        cx.notify();
19240    }
19241
19242    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19243        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19244            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19245                && let Some(dir) = file.abs_path(cx).parent()
19246            {
19247                return Some(dir.to_owned());
19248            }
19249
19250            if let Some(project_path) = buffer.read(cx).project_path(cx) {
19251                return Some(project_path.path.to_path_buf());
19252            }
19253        }
19254
19255        None
19256    }
19257
19258    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19259        self.active_excerpt(cx)?
19260            .1
19261            .read(cx)
19262            .file()
19263            .and_then(|f| f.as_local())
19264    }
19265
19266    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19267        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19268            let buffer = buffer.read(cx);
19269            if let Some(project_path) = buffer.project_path(cx) {
19270                let project = self.project()?.read(cx);
19271                project.absolute_path(&project_path, cx)
19272            } else {
19273                buffer
19274                    .file()
19275                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19276            }
19277        })
19278    }
19279
19280    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19281        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19282            let project_path = buffer.read(cx).project_path(cx)?;
19283            let project = self.project()?.read(cx);
19284            let entry = project.entry_for_path(&project_path, cx)?;
19285            let path = entry.path.to_path_buf();
19286            Some(path)
19287        })
19288    }
19289
19290    pub fn reveal_in_finder(
19291        &mut self,
19292        _: &RevealInFileManager,
19293        _window: &mut Window,
19294        cx: &mut Context<Self>,
19295    ) {
19296        if let Some(target) = self.target_file(cx) {
19297            cx.reveal_path(&target.abs_path(cx));
19298        }
19299    }
19300
19301    pub fn copy_path(
19302        &mut self,
19303        _: &zed_actions::workspace::CopyPath,
19304        _window: &mut Window,
19305        cx: &mut Context<Self>,
19306    ) {
19307        if let Some(path) = self.target_file_abs_path(cx)
19308            && let Some(path) = path.to_str()
19309        {
19310            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19311        } else {
19312            cx.propagate();
19313        }
19314    }
19315
19316    pub fn copy_relative_path(
19317        &mut self,
19318        _: &zed_actions::workspace::CopyRelativePath,
19319        _window: &mut Window,
19320        cx: &mut Context<Self>,
19321    ) {
19322        if let Some(path) = self.target_file_path(cx)
19323            && let Some(path) = path.to_str()
19324        {
19325            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19326        } else {
19327            cx.propagate();
19328        }
19329    }
19330
19331    /// Returns the project path for the editor's buffer, if any buffer is
19332    /// opened in the editor.
19333    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19334        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19335            buffer.read(cx).project_path(cx)
19336        } else {
19337            None
19338        }
19339    }
19340
19341    // Returns true if the editor handled a go-to-line request
19342    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19343        maybe!({
19344            let breakpoint_store = self.breakpoint_store.as_ref()?;
19345
19346            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19347            else {
19348                self.clear_row_highlights::<ActiveDebugLine>();
19349                return None;
19350            };
19351
19352            let position = active_stack_frame.position;
19353            let buffer_id = position.buffer_id?;
19354            let snapshot = self
19355                .project
19356                .as_ref()?
19357                .read(cx)
19358                .buffer_for_id(buffer_id, cx)?
19359                .read(cx)
19360                .snapshot();
19361
19362            let mut handled = false;
19363            for (id, ExcerptRange { context, .. }) in
19364                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19365            {
19366                if context.start.cmp(&position, &snapshot).is_ge()
19367                    || context.end.cmp(&position, &snapshot).is_lt()
19368                {
19369                    continue;
19370                }
19371                let snapshot = self.buffer.read(cx).snapshot(cx);
19372                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19373
19374                handled = true;
19375                self.clear_row_highlights::<ActiveDebugLine>();
19376
19377                self.go_to_line::<ActiveDebugLine>(
19378                    multibuffer_anchor,
19379                    Some(cx.theme().colors().editor_debugger_active_line_background),
19380                    window,
19381                    cx,
19382                );
19383
19384                cx.notify();
19385            }
19386
19387            handled.then_some(())
19388        })
19389        .is_some()
19390    }
19391
19392    pub fn copy_file_name_without_extension(
19393        &mut self,
19394        _: &CopyFileNameWithoutExtension,
19395        _: &mut Window,
19396        cx: &mut Context<Self>,
19397    ) {
19398        if let Some(file) = self.target_file(cx)
19399            && let Some(file_stem) = file.path().file_stem()
19400            && let Some(name) = file_stem.to_str()
19401        {
19402            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19403        }
19404    }
19405
19406    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19407        if let Some(file) = self.target_file(cx)
19408            && let Some(file_name) = file.path().file_name()
19409            && let Some(name) = file_name.to_str()
19410        {
19411            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19412        }
19413    }
19414
19415    pub fn toggle_git_blame(
19416        &mut self,
19417        _: &::git::Blame,
19418        window: &mut Window,
19419        cx: &mut Context<Self>,
19420    ) {
19421        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19422
19423        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19424            self.start_git_blame(true, window, cx);
19425        }
19426
19427        cx.notify();
19428    }
19429
19430    pub fn toggle_git_blame_inline(
19431        &mut self,
19432        _: &ToggleGitBlameInline,
19433        window: &mut Window,
19434        cx: &mut Context<Self>,
19435    ) {
19436        self.toggle_git_blame_inline_internal(true, window, cx);
19437        cx.notify();
19438    }
19439
19440    pub fn open_git_blame_commit(
19441        &mut self,
19442        _: &OpenGitBlameCommit,
19443        window: &mut Window,
19444        cx: &mut Context<Self>,
19445    ) {
19446        self.open_git_blame_commit_internal(window, cx);
19447    }
19448
19449    fn open_git_blame_commit_internal(
19450        &mut self,
19451        window: &mut Window,
19452        cx: &mut Context<Self>,
19453    ) -> Option<()> {
19454        let blame = self.blame.as_ref()?;
19455        let snapshot = self.snapshot(window, cx);
19456        let cursor = self.selections.newest::<Point>(cx).head();
19457        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19458        let (_, blame_entry) = blame
19459            .update(cx, |blame, cx| {
19460                blame
19461                    .blame_for_rows(
19462                        &[RowInfo {
19463                            buffer_id: Some(buffer.remote_id()),
19464                            buffer_row: Some(point.row),
19465                            ..Default::default()
19466                        }],
19467                        cx,
19468                    )
19469                    .next()
19470            })
19471            .flatten()?;
19472        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19473        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19474        let workspace = self.workspace()?.downgrade();
19475        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19476        None
19477    }
19478
19479    pub fn git_blame_inline_enabled(&self) -> bool {
19480        self.git_blame_inline_enabled
19481    }
19482
19483    pub fn toggle_selection_menu(
19484        &mut self,
19485        _: &ToggleSelectionMenu,
19486        _: &mut Window,
19487        cx: &mut Context<Self>,
19488    ) {
19489        self.show_selection_menu = self
19490            .show_selection_menu
19491            .map(|show_selections_menu| !show_selections_menu)
19492            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19493
19494        cx.notify();
19495    }
19496
19497    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19498        self.show_selection_menu
19499            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19500    }
19501
19502    fn start_git_blame(
19503        &mut self,
19504        user_triggered: bool,
19505        window: &mut Window,
19506        cx: &mut Context<Self>,
19507    ) {
19508        if let Some(project) = self.project() {
19509            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19510                && buffer.read(cx).file().is_none()
19511            {
19512                return;
19513            }
19514
19515            let focused = self.focus_handle(cx).contains_focused(window, cx);
19516
19517            let project = project.clone();
19518            let blame = cx
19519                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19520            self.blame_subscription =
19521                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19522            self.blame = Some(blame);
19523        }
19524    }
19525
19526    fn toggle_git_blame_inline_internal(
19527        &mut self,
19528        user_triggered: bool,
19529        window: &mut Window,
19530        cx: &mut Context<Self>,
19531    ) {
19532        if self.git_blame_inline_enabled {
19533            self.git_blame_inline_enabled = false;
19534            self.show_git_blame_inline = false;
19535            self.show_git_blame_inline_delay_task.take();
19536        } else {
19537            self.git_blame_inline_enabled = true;
19538            self.start_git_blame_inline(user_triggered, window, cx);
19539        }
19540
19541        cx.notify();
19542    }
19543
19544    fn start_git_blame_inline(
19545        &mut self,
19546        user_triggered: bool,
19547        window: &mut Window,
19548        cx: &mut Context<Self>,
19549    ) {
19550        self.start_git_blame(user_triggered, window, cx);
19551
19552        if ProjectSettings::get_global(cx)
19553            .git
19554            .inline_blame_delay()
19555            .is_some()
19556        {
19557            self.start_inline_blame_timer(window, cx);
19558        } else {
19559            self.show_git_blame_inline = true
19560        }
19561    }
19562
19563    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19564        self.blame.as_ref()
19565    }
19566
19567    pub fn show_git_blame_gutter(&self) -> bool {
19568        self.show_git_blame_gutter
19569    }
19570
19571    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19572        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19573    }
19574
19575    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19576        self.show_git_blame_inline
19577            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19578            && !self.newest_selection_head_on_empty_line(cx)
19579            && self.has_blame_entries(cx)
19580    }
19581
19582    fn has_blame_entries(&self, cx: &App) -> bool {
19583        self.blame()
19584            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19585    }
19586
19587    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19588        let cursor_anchor = self.selections.newest_anchor().head();
19589
19590        let snapshot = self.buffer.read(cx).snapshot(cx);
19591        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19592
19593        snapshot.line_len(buffer_row) == 0
19594    }
19595
19596    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19597        let buffer_and_selection = maybe!({
19598            let selection = self.selections.newest::<Point>(cx);
19599            let selection_range = selection.range();
19600
19601            let multi_buffer = self.buffer().read(cx);
19602            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19603            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19604
19605            let (buffer, range, _) = if selection.reversed {
19606                buffer_ranges.first()
19607            } else {
19608                buffer_ranges.last()
19609            }?;
19610
19611            let selection = text::ToPoint::to_point(&range.start, buffer).row
19612                ..text::ToPoint::to_point(&range.end, buffer).row;
19613            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19614        });
19615
19616        let Some((buffer, selection)) = buffer_and_selection else {
19617            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19618        };
19619
19620        let Some(project) = self.project() else {
19621            return Task::ready(Err(anyhow!("editor does not have project")));
19622        };
19623
19624        project.update(cx, |project, cx| {
19625            project.get_permalink_to_line(&buffer, selection, cx)
19626        })
19627    }
19628
19629    pub fn copy_permalink_to_line(
19630        &mut self,
19631        _: &CopyPermalinkToLine,
19632        window: &mut Window,
19633        cx: &mut Context<Self>,
19634    ) {
19635        let permalink_task = self.get_permalink_to_line(cx);
19636        let workspace = self.workspace();
19637
19638        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19639            Ok(permalink) => {
19640                cx.update(|_, cx| {
19641                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19642                })
19643                .ok();
19644            }
19645            Err(err) => {
19646                let message = format!("Failed to copy permalink: {err}");
19647
19648                anyhow::Result::<()>::Err(err).log_err();
19649
19650                if let Some(workspace) = workspace {
19651                    workspace
19652                        .update_in(cx, |workspace, _, cx| {
19653                            struct CopyPermalinkToLine;
19654
19655                            workspace.show_toast(
19656                                Toast::new(
19657                                    NotificationId::unique::<CopyPermalinkToLine>(),
19658                                    message,
19659                                ),
19660                                cx,
19661                            )
19662                        })
19663                        .ok();
19664                }
19665            }
19666        })
19667        .detach();
19668    }
19669
19670    pub fn copy_file_location(
19671        &mut self,
19672        _: &CopyFileLocation,
19673        _: &mut Window,
19674        cx: &mut Context<Self>,
19675    ) {
19676        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19677        if let Some(file) = self.target_file(cx)
19678            && let Some(path) = file.path().to_str()
19679        {
19680            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19681        }
19682    }
19683
19684    pub fn open_permalink_to_line(
19685        &mut self,
19686        _: &OpenPermalinkToLine,
19687        window: &mut Window,
19688        cx: &mut Context<Self>,
19689    ) {
19690        let permalink_task = self.get_permalink_to_line(cx);
19691        let workspace = self.workspace();
19692
19693        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19694            Ok(permalink) => {
19695                cx.update(|_, cx| {
19696                    cx.open_url(permalink.as_ref());
19697                })
19698                .ok();
19699            }
19700            Err(err) => {
19701                let message = format!("Failed to open permalink: {err}");
19702
19703                anyhow::Result::<()>::Err(err).log_err();
19704
19705                if let Some(workspace) = workspace {
19706                    workspace
19707                        .update(cx, |workspace, cx| {
19708                            struct OpenPermalinkToLine;
19709
19710                            workspace.show_toast(
19711                                Toast::new(
19712                                    NotificationId::unique::<OpenPermalinkToLine>(),
19713                                    message,
19714                                ),
19715                                cx,
19716                            )
19717                        })
19718                        .ok();
19719                }
19720            }
19721        })
19722        .detach();
19723    }
19724
19725    pub fn insert_uuid_v4(
19726        &mut self,
19727        _: &InsertUuidV4,
19728        window: &mut Window,
19729        cx: &mut Context<Self>,
19730    ) {
19731        self.insert_uuid(UuidVersion::V4, window, cx);
19732    }
19733
19734    pub fn insert_uuid_v7(
19735        &mut self,
19736        _: &InsertUuidV7,
19737        window: &mut Window,
19738        cx: &mut Context<Self>,
19739    ) {
19740        self.insert_uuid(UuidVersion::V7, window, cx);
19741    }
19742
19743    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19744        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19745        self.transact(window, cx, |this, window, cx| {
19746            let edits = this
19747                .selections
19748                .all::<Point>(cx)
19749                .into_iter()
19750                .map(|selection| {
19751                    let uuid = match version {
19752                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19753                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19754                    };
19755
19756                    (selection.range(), uuid.to_string())
19757                });
19758            this.edit(edits, cx);
19759            this.refresh_edit_prediction(true, false, window, cx);
19760        });
19761    }
19762
19763    pub fn open_selections_in_multibuffer(
19764        &mut self,
19765        _: &OpenSelectionsInMultibuffer,
19766        window: &mut Window,
19767        cx: &mut Context<Self>,
19768    ) {
19769        let multibuffer = self.buffer.read(cx);
19770
19771        let Some(buffer) = multibuffer.as_singleton() else {
19772            return;
19773        };
19774
19775        let Some(workspace) = self.workspace() else {
19776            return;
19777        };
19778
19779        let title = multibuffer.title(cx).to_string();
19780
19781        let locations = self
19782            .selections
19783            .all_anchors(cx)
19784            .iter()
19785            .map(|selection| Location {
19786                buffer: buffer.clone(),
19787                range: selection.start.text_anchor..selection.end.text_anchor,
19788            })
19789            .collect::<Vec<_>>();
19790
19791        cx.spawn_in(window, async move |_, cx| {
19792            workspace.update_in(cx, |workspace, window, cx| {
19793                Self::open_locations_in_multibuffer(
19794                    workspace,
19795                    locations,
19796                    format!("Selections for '{title}'"),
19797                    false,
19798                    MultibufferSelectionMode::All,
19799                    window,
19800                    cx,
19801                );
19802            })
19803        })
19804        .detach();
19805    }
19806
19807    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19808    /// last highlight added will be used.
19809    ///
19810    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19811    pub fn highlight_rows<T: 'static>(
19812        &mut self,
19813        range: Range<Anchor>,
19814        color: Hsla,
19815        options: RowHighlightOptions,
19816        cx: &mut Context<Self>,
19817    ) {
19818        let snapshot = self.buffer().read(cx).snapshot(cx);
19819        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19820        let ix = row_highlights.binary_search_by(|highlight| {
19821            Ordering::Equal
19822                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19823                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19824        });
19825
19826        if let Err(mut ix) = ix {
19827            let index = post_inc(&mut self.highlight_order);
19828
19829            // If this range intersects with the preceding highlight, then merge it with
19830            // the preceding highlight. Otherwise insert a new highlight.
19831            let mut merged = false;
19832            if ix > 0 {
19833                let prev_highlight = &mut row_highlights[ix - 1];
19834                if prev_highlight
19835                    .range
19836                    .end
19837                    .cmp(&range.start, &snapshot)
19838                    .is_ge()
19839                {
19840                    ix -= 1;
19841                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19842                        prev_highlight.range.end = range.end;
19843                    }
19844                    merged = true;
19845                    prev_highlight.index = index;
19846                    prev_highlight.color = color;
19847                    prev_highlight.options = options;
19848                }
19849            }
19850
19851            if !merged {
19852                row_highlights.insert(
19853                    ix,
19854                    RowHighlight {
19855                        range,
19856                        index,
19857                        color,
19858                        options,
19859                        type_id: TypeId::of::<T>(),
19860                    },
19861                );
19862            }
19863
19864            // If any of the following highlights intersect with this one, merge them.
19865            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19866                let highlight = &row_highlights[ix];
19867                if next_highlight
19868                    .range
19869                    .start
19870                    .cmp(&highlight.range.end, &snapshot)
19871                    .is_le()
19872                {
19873                    if next_highlight
19874                        .range
19875                        .end
19876                        .cmp(&highlight.range.end, &snapshot)
19877                        .is_gt()
19878                    {
19879                        row_highlights[ix].range.end = next_highlight.range.end;
19880                    }
19881                    row_highlights.remove(ix + 1);
19882                } else {
19883                    break;
19884                }
19885            }
19886        }
19887    }
19888
19889    /// Remove any highlighted row ranges of the given type that intersect the
19890    /// given ranges.
19891    pub fn remove_highlighted_rows<T: 'static>(
19892        &mut self,
19893        ranges_to_remove: Vec<Range<Anchor>>,
19894        cx: &mut Context<Self>,
19895    ) {
19896        let snapshot = self.buffer().read(cx).snapshot(cx);
19897        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19898        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19899        row_highlights.retain(|highlight| {
19900            while let Some(range_to_remove) = ranges_to_remove.peek() {
19901                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19902                    Ordering::Less | Ordering::Equal => {
19903                        ranges_to_remove.next();
19904                    }
19905                    Ordering::Greater => {
19906                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19907                            Ordering::Less | Ordering::Equal => {
19908                                return false;
19909                            }
19910                            Ordering::Greater => break,
19911                        }
19912                    }
19913                }
19914            }
19915
19916            true
19917        })
19918    }
19919
19920    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19921    pub fn clear_row_highlights<T: 'static>(&mut self) {
19922        self.highlighted_rows.remove(&TypeId::of::<T>());
19923    }
19924
19925    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19926    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19927        self.highlighted_rows
19928            .get(&TypeId::of::<T>())
19929            .map_or(&[] as &[_], |vec| vec.as_slice())
19930            .iter()
19931            .map(|highlight| (highlight.range.clone(), highlight.color))
19932    }
19933
19934    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19935    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19936    /// Allows to ignore certain kinds of highlights.
19937    pub fn highlighted_display_rows(
19938        &self,
19939        window: &mut Window,
19940        cx: &mut App,
19941    ) -> BTreeMap<DisplayRow, LineHighlight> {
19942        let snapshot = self.snapshot(window, cx);
19943        let mut used_highlight_orders = HashMap::default();
19944        self.highlighted_rows
19945            .iter()
19946            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19947            .fold(
19948                BTreeMap::<DisplayRow, LineHighlight>::new(),
19949                |mut unique_rows, highlight| {
19950                    let start = highlight.range.start.to_display_point(&snapshot);
19951                    let end = highlight.range.end.to_display_point(&snapshot);
19952                    let start_row = start.row().0;
19953                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19954                        && end.column() == 0
19955                    {
19956                        end.row().0.saturating_sub(1)
19957                    } else {
19958                        end.row().0
19959                    };
19960                    for row in start_row..=end_row {
19961                        let used_index =
19962                            used_highlight_orders.entry(row).or_insert(highlight.index);
19963                        if highlight.index >= *used_index {
19964                            *used_index = highlight.index;
19965                            unique_rows.insert(
19966                                DisplayRow(row),
19967                                LineHighlight {
19968                                    include_gutter: highlight.options.include_gutter,
19969                                    border: None,
19970                                    background: highlight.color.into(),
19971                                    type_id: Some(highlight.type_id),
19972                                },
19973                            );
19974                        }
19975                    }
19976                    unique_rows
19977                },
19978            )
19979    }
19980
19981    pub fn highlighted_display_row_for_autoscroll(
19982        &self,
19983        snapshot: &DisplaySnapshot,
19984    ) -> Option<DisplayRow> {
19985        self.highlighted_rows
19986            .values()
19987            .flat_map(|highlighted_rows| highlighted_rows.iter())
19988            .filter_map(|highlight| {
19989                if highlight.options.autoscroll {
19990                    Some(highlight.range.start.to_display_point(snapshot).row())
19991                } else {
19992                    None
19993                }
19994            })
19995            .min()
19996    }
19997
19998    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19999        self.highlight_background::<SearchWithinRange>(
20000            ranges,
20001            |colors| colors.colors().editor_document_highlight_read_background,
20002            cx,
20003        )
20004    }
20005
20006    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20007        self.breadcrumb_header = Some(new_header);
20008    }
20009
20010    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20011        self.clear_background_highlights::<SearchWithinRange>(cx);
20012    }
20013
20014    pub fn highlight_background<T: 'static>(
20015        &mut self,
20016        ranges: &[Range<Anchor>],
20017        color_fetcher: fn(&Theme) -> Hsla,
20018        cx: &mut Context<Self>,
20019    ) {
20020        self.background_highlights.insert(
20021            HighlightKey::Type(TypeId::of::<T>()),
20022            (color_fetcher, Arc::from(ranges)),
20023        );
20024        self.scrollbar_marker_state.dirty = true;
20025        cx.notify();
20026    }
20027
20028    pub fn highlight_background_key<T: 'static>(
20029        &mut self,
20030        key: usize,
20031        ranges: &[Range<Anchor>],
20032        color_fetcher: fn(&Theme) -> Hsla,
20033        cx: &mut Context<Self>,
20034    ) {
20035        self.background_highlights.insert(
20036            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20037            (color_fetcher, Arc::from(ranges)),
20038        );
20039        self.scrollbar_marker_state.dirty = true;
20040        cx.notify();
20041    }
20042
20043    pub fn clear_background_highlights<T: 'static>(
20044        &mut self,
20045        cx: &mut Context<Self>,
20046    ) -> Option<BackgroundHighlight> {
20047        let text_highlights = self
20048            .background_highlights
20049            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20050        if !text_highlights.1.is_empty() {
20051            self.scrollbar_marker_state.dirty = true;
20052            cx.notify();
20053        }
20054        Some(text_highlights)
20055    }
20056
20057    pub fn highlight_gutter<T: 'static>(
20058        &mut self,
20059        ranges: impl Into<Vec<Range<Anchor>>>,
20060        color_fetcher: fn(&App) -> Hsla,
20061        cx: &mut Context<Self>,
20062    ) {
20063        self.gutter_highlights
20064            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20065        cx.notify();
20066    }
20067
20068    pub fn clear_gutter_highlights<T: 'static>(
20069        &mut self,
20070        cx: &mut Context<Self>,
20071    ) -> Option<GutterHighlight> {
20072        cx.notify();
20073        self.gutter_highlights.remove(&TypeId::of::<T>())
20074    }
20075
20076    pub fn insert_gutter_highlight<T: 'static>(
20077        &mut self,
20078        range: Range<Anchor>,
20079        color_fetcher: fn(&App) -> Hsla,
20080        cx: &mut Context<Self>,
20081    ) {
20082        let snapshot = self.buffer().read(cx).snapshot(cx);
20083        let mut highlights = self
20084            .gutter_highlights
20085            .remove(&TypeId::of::<T>())
20086            .map(|(_, highlights)| highlights)
20087            .unwrap_or_default();
20088        let ix = highlights.binary_search_by(|highlight| {
20089            Ordering::Equal
20090                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20091                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20092        });
20093        if let Err(ix) = ix {
20094            highlights.insert(ix, range);
20095        }
20096        self.gutter_highlights
20097            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20098    }
20099
20100    pub fn remove_gutter_highlights<T: 'static>(
20101        &mut self,
20102        ranges_to_remove: Vec<Range<Anchor>>,
20103        cx: &mut Context<Self>,
20104    ) {
20105        let snapshot = self.buffer().read(cx).snapshot(cx);
20106        let Some((color_fetcher, mut gutter_highlights)) =
20107            self.gutter_highlights.remove(&TypeId::of::<T>())
20108        else {
20109            return;
20110        };
20111        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20112        gutter_highlights.retain(|highlight| {
20113            while let Some(range_to_remove) = ranges_to_remove.peek() {
20114                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20115                    Ordering::Less | Ordering::Equal => {
20116                        ranges_to_remove.next();
20117                    }
20118                    Ordering::Greater => {
20119                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20120                            Ordering::Less | Ordering::Equal => {
20121                                return false;
20122                            }
20123                            Ordering::Greater => break,
20124                        }
20125                    }
20126                }
20127            }
20128
20129            true
20130        });
20131        self.gutter_highlights
20132            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20133    }
20134
20135    #[cfg(feature = "test-support")]
20136    pub fn all_text_highlights(
20137        &self,
20138        window: &mut Window,
20139        cx: &mut Context<Self>,
20140    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20141        let snapshot = self.snapshot(window, cx);
20142        self.display_map.update(cx, |display_map, _| {
20143            display_map
20144                .all_text_highlights()
20145                .map(|highlight| {
20146                    let (style, ranges) = highlight.as_ref();
20147                    (
20148                        *style,
20149                        ranges
20150                            .iter()
20151                            .map(|range| range.clone().to_display_points(&snapshot))
20152                            .collect(),
20153                    )
20154                })
20155                .collect()
20156        })
20157    }
20158
20159    #[cfg(feature = "test-support")]
20160    pub fn all_text_background_highlights(
20161        &self,
20162        window: &mut Window,
20163        cx: &mut Context<Self>,
20164    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20165        let snapshot = self.snapshot(window, cx);
20166        let buffer = &snapshot.buffer_snapshot;
20167        let start = buffer.anchor_before(0);
20168        let end = buffer.anchor_after(buffer.len());
20169        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20170    }
20171
20172    #[cfg(any(test, feature = "test-support"))]
20173    pub fn sorted_background_highlights_in_range(
20174        &self,
20175        search_range: Range<Anchor>,
20176        display_snapshot: &DisplaySnapshot,
20177        theme: &Theme,
20178    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20179        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20180        res.sort_by(|a, b| {
20181            a.0.start
20182                .cmp(&b.0.start)
20183                .then_with(|| a.0.end.cmp(&b.0.end))
20184                .then_with(|| a.1.cmp(&b.1))
20185        });
20186        res
20187    }
20188
20189    #[cfg(feature = "test-support")]
20190    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20191        let snapshot = self.buffer().read(cx).snapshot(cx);
20192
20193        let highlights = self
20194            .background_highlights
20195            .get(&HighlightKey::Type(TypeId::of::<
20196                items::BufferSearchHighlights,
20197            >()));
20198
20199        if let Some((_color, ranges)) = highlights {
20200            ranges
20201                .iter()
20202                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20203                .collect_vec()
20204        } else {
20205            vec![]
20206        }
20207    }
20208
20209    fn document_highlights_for_position<'a>(
20210        &'a self,
20211        position: Anchor,
20212        buffer: &'a MultiBufferSnapshot,
20213    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20214        let read_highlights = self
20215            .background_highlights
20216            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20217            .map(|h| &h.1);
20218        let write_highlights = self
20219            .background_highlights
20220            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20221            .map(|h| &h.1);
20222        let left_position = position.bias_left(buffer);
20223        let right_position = position.bias_right(buffer);
20224        read_highlights
20225            .into_iter()
20226            .chain(write_highlights)
20227            .flat_map(move |ranges| {
20228                let start_ix = match ranges.binary_search_by(|probe| {
20229                    let cmp = probe.end.cmp(&left_position, buffer);
20230                    if cmp.is_ge() {
20231                        Ordering::Greater
20232                    } else {
20233                        Ordering::Less
20234                    }
20235                }) {
20236                    Ok(i) | Err(i) => i,
20237                };
20238
20239                ranges[start_ix..]
20240                    .iter()
20241                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20242            })
20243    }
20244
20245    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20246        self.background_highlights
20247            .get(&HighlightKey::Type(TypeId::of::<T>()))
20248            .is_some_and(|(_, highlights)| !highlights.is_empty())
20249    }
20250
20251    /// Returns all background highlights for a given range.
20252    ///
20253    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20254    pub fn background_highlights_in_range(
20255        &self,
20256        search_range: Range<Anchor>,
20257        display_snapshot: &DisplaySnapshot,
20258        theme: &Theme,
20259    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20260        let mut results = Vec::new();
20261        for (color_fetcher, ranges) in self.background_highlights.values() {
20262            let color = color_fetcher(theme);
20263            let start_ix = match ranges.binary_search_by(|probe| {
20264                let cmp = probe
20265                    .end
20266                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20267                if cmp.is_gt() {
20268                    Ordering::Greater
20269                } else {
20270                    Ordering::Less
20271                }
20272            }) {
20273                Ok(i) | Err(i) => i,
20274            };
20275            for range in &ranges[start_ix..] {
20276                if range
20277                    .start
20278                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20279                    .is_ge()
20280                {
20281                    break;
20282                }
20283
20284                let start = range.start.to_display_point(display_snapshot);
20285                let end = range.end.to_display_point(display_snapshot);
20286                results.push((start..end, color))
20287            }
20288        }
20289        results
20290    }
20291
20292    pub fn gutter_highlights_in_range(
20293        &self,
20294        search_range: Range<Anchor>,
20295        display_snapshot: &DisplaySnapshot,
20296        cx: &App,
20297    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20298        let mut results = Vec::new();
20299        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20300            let color = color_fetcher(cx);
20301            let start_ix = match ranges.binary_search_by(|probe| {
20302                let cmp = probe
20303                    .end
20304                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20305                if cmp.is_gt() {
20306                    Ordering::Greater
20307                } else {
20308                    Ordering::Less
20309                }
20310            }) {
20311                Ok(i) | Err(i) => i,
20312            };
20313            for range in &ranges[start_ix..] {
20314                if range
20315                    .start
20316                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20317                    .is_ge()
20318                {
20319                    break;
20320                }
20321
20322                let start = range.start.to_display_point(display_snapshot);
20323                let end = range.end.to_display_point(display_snapshot);
20324                results.push((start..end, color))
20325            }
20326        }
20327        results
20328    }
20329
20330    /// Get the text ranges corresponding to the redaction query
20331    pub fn redacted_ranges(
20332        &self,
20333        search_range: Range<Anchor>,
20334        display_snapshot: &DisplaySnapshot,
20335        cx: &App,
20336    ) -> Vec<Range<DisplayPoint>> {
20337        display_snapshot
20338            .buffer_snapshot
20339            .redacted_ranges(search_range, |file| {
20340                if let Some(file) = file {
20341                    file.is_private()
20342                        && EditorSettings::get(
20343                            Some(SettingsLocation {
20344                                worktree_id: file.worktree_id(cx),
20345                                path: file.path().as_ref(),
20346                            }),
20347                            cx,
20348                        )
20349                        .redact_private_values
20350                } else {
20351                    false
20352                }
20353            })
20354            .map(|range| {
20355                range.start.to_display_point(display_snapshot)
20356                    ..range.end.to_display_point(display_snapshot)
20357            })
20358            .collect()
20359    }
20360
20361    pub fn highlight_text_key<T: 'static>(
20362        &mut self,
20363        key: usize,
20364        ranges: Vec<Range<Anchor>>,
20365        style: HighlightStyle,
20366        cx: &mut Context<Self>,
20367    ) {
20368        self.display_map.update(cx, |map, _| {
20369            map.highlight_text(
20370                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20371                ranges,
20372                style,
20373            );
20374        });
20375        cx.notify();
20376    }
20377
20378    pub fn highlight_text<T: 'static>(
20379        &mut self,
20380        ranges: Vec<Range<Anchor>>,
20381        style: HighlightStyle,
20382        cx: &mut Context<Self>,
20383    ) {
20384        self.display_map.update(cx, |map, _| {
20385            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20386        });
20387        cx.notify();
20388    }
20389
20390    pub(crate) fn highlight_inlays<T: 'static>(
20391        &mut self,
20392        highlights: Vec<InlayHighlight>,
20393        style: HighlightStyle,
20394        cx: &mut Context<Self>,
20395    ) {
20396        self.display_map.update(cx, |map, _| {
20397            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20398        });
20399        cx.notify();
20400    }
20401
20402    pub fn text_highlights<'a, T: 'static>(
20403        &'a self,
20404        cx: &'a App,
20405    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20406        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20407    }
20408
20409    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20410        let cleared = self
20411            .display_map
20412            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20413        if cleared {
20414            cx.notify();
20415        }
20416    }
20417
20418    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20419        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20420            && self.focus_handle.is_focused(window)
20421    }
20422
20423    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20424        self.show_cursor_when_unfocused = is_enabled;
20425        cx.notify();
20426    }
20427
20428    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20429        cx.notify();
20430    }
20431
20432    fn on_debug_session_event(
20433        &mut self,
20434        _session: Entity<Session>,
20435        event: &SessionEvent,
20436        cx: &mut Context<Self>,
20437    ) {
20438        if let SessionEvent::InvalidateInlineValue = event {
20439            self.refresh_inline_values(cx);
20440        }
20441    }
20442
20443    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20444        let Some(project) = self.project.clone() else {
20445            return;
20446        };
20447
20448        if !self.inline_value_cache.enabled {
20449            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20450            self.splice_inlays(&inlays, Vec::new(), cx);
20451            return;
20452        }
20453
20454        let current_execution_position = self
20455            .highlighted_rows
20456            .get(&TypeId::of::<ActiveDebugLine>())
20457            .and_then(|lines| lines.last().map(|line| line.range.end));
20458
20459        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20460            let inline_values = editor
20461                .update(cx, |editor, cx| {
20462                    let Some(current_execution_position) = current_execution_position else {
20463                        return Some(Task::ready(Ok(Vec::new())));
20464                    };
20465
20466                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20467                        let snapshot = buffer.snapshot(cx);
20468
20469                        let excerpt = snapshot.excerpt_containing(
20470                            current_execution_position..current_execution_position,
20471                        )?;
20472
20473                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20474                    })?;
20475
20476                    let range =
20477                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20478
20479                    project.inline_values(buffer, range, cx)
20480                })
20481                .ok()
20482                .flatten()?
20483                .await
20484                .context("refreshing debugger inlays")
20485                .log_err()?;
20486
20487            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20488
20489            for (buffer_id, inline_value) in inline_values
20490                .into_iter()
20491                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20492            {
20493                buffer_inline_values
20494                    .entry(buffer_id)
20495                    .or_default()
20496                    .push(inline_value);
20497            }
20498
20499            editor
20500                .update(cx, |editor, cx| {
20501                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20502                    let mut new_inlays = Vec::default();
20503
20504                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20505                        let buffer_id = buffer_snapshot.remote_id();
20506                        buffer_inline_values
20507                            .get(&buffer_id)
20508                            .into_iter()
20509                            .flatten()
20510                            .for_each(|hint| {
20511                                let inlay = Inlay::debugger(
20512                                    post_inc(&mut editor.next_inlay_id),
20513                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20514                                    hint.text(),
20515                                );
20516                                if !inlay.text.chars().contains(&'\n') {
20517                                    new_inlays.push(inlay);
20518                                }
20519                            });
20520                    }
20521
20522                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20523                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20524
20525                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20526                })
20527                .ok()?;
20528            Some(())
20529        });
20530    }
20531
20532    fn on_buffer_event(
20533        &mut self,
20534        multibuffer: &Entity<MultiBuffer>,
20535        event: &multi_buffer::Event,
20536        window: &mut Window,
20537        cx: &mut Context<Self>,
20538    ) {
20539        match event {
20540            multi_buffer::Event::Edited {
20541                singleton_buffer_edited,
20542                edited_buffer,
20543            } => {
20544                self.scrollbar_marker_state.dirty = true;
20545                self.active_indent_guides_state.dirty = true;
20546                self.refresh_active_diagnostics(cx);
20547                self.refresh_code_actions(window, cx);
20548                self.refresh_selected_text_highlights(true, window, cx);
20549                self.refresh_single_line_folds(window, cx);
20550                refresh_matching_bracket_highlights(self, window, cx);
20551                if self.has_active_edit_prediction() {
20552                    self.update_visible_edit_prediction(window, cx);
20553                }
20554                if let Some(project) = self.project.as_ref()
20555                    && let Some(edited_buffer) = edited_buffer
20556                {
20557                    project.update(cx, |project, cx| {
20558                        self.registered_buffers
20559                            .entry(edited_buffer.read(cx).remote_id())
20560                            .or_insert_with(|| {
20561                                project.register_buffer_with_language_servers(edited_buffer, cx)
20562                            });
20563                    });
20564                }
20565                cx.emit(EditorEvent::BufferEdited);
20566                cx.emit(SearchEvent::MatchesInvalidated);
20567
20568                if let Some(buffer) = edited_buffer {
20569                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20570                }
20571
20572                if *singleton_buffer_edited {
20573                    if let Some(buffer) = edited_buffer
20574                        && buffer.read(cx).file().is_none()
20575                    {
20576                        cx.emit(EditorEvent::TitleChanged);
20577                    }
20578                    if let Some(project) = &self.project {
20579                        #[allow(clippy::mutable_key_type)]
20580                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20581                            multibuffer
20582                                .all_buffers()
20583                                .into_iter()
20584                                .filter_map(|buffer| {
20585                                    buffer.update(cx, |buffer, cx| {
20586                                        let language = buffer.language()?;
20587                                        let should_discard = project.update(cx, |project, cx| {
20588                                            project.is_local()
20589                                                && !project.has_language_servers_for(buffer, cx)
20590                                        });
20591                                        should_discard.not().then_some(language.clone())
20592                                    })
20593                                })
20594                                .collect::<HashSet<_>>()
20595                        });
20596                        if !languages_affected.is_empty() {
20597                            self.refresh_inlay_hints(
20598                                InlayHintRefreshReason::BufferEdited(languages_affected),
20599                                cx,
20600                            );
20601                        }
20602                    }
20603                }
20604
20605                let Some(project) = &self.project else { return };
20606                let (telemetry, is_via_ssh) = {
20607                    let project = project.read(cx);
20608                    let telemetry = project.client().telemetry().clone();
20609                    let is_via_ssh = project.is_via_remote_server();
20610                    (telemetry, is_via_ssh)
20611                };
20612                refresh_linked_ranges(self, window, cx);
20613                telemetry.log_edit_event("editor", is_via_ssh);
20614            }
20615            multi_buffer::Event::ExcerptsAdded {
20616                buffer,
20617                predecessor,
20618                excerpts,
20619            } => {
20620                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20621                let buffer_id = buffer.read(cx).remote_id();
20622                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20623                    && let Some(project) = &self.project
20624                {
20625                    update_uncommitted_diff_for_buffer(
20626                        cx.entity(),
20627                        project,
20628                        [buffer.clone()],
20629                        self.buffer.clone(),
20630                        cx,
20631                    )
20632                    .detach();
20633                }
20634                if self.active_diagnostics != ActiveDiagnostic::All {
20635                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20636                }
20637                cx.emit(EditorEvent::ExcerptsAdded {
20638                    buffer: buffer.clone(),
20639                    predecessor: *predecessor,
20640                    excerpts: excerpts.clone(),
20641                });
20642                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20643            }
20644            multi_buffer::Event::ExcerptsRemoved {
20645                ids,
20646                removed_buffer_ids,
20647            } => {
20648                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20649                let buffer = self.buffer.read(cx);
20650                self.registered_buffers
20651                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20652                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20653                cx.emit(EditorEvent::ExcerptsRemoved {
20654                    ids: ids.clone(),
20655                    removed_buffer_ids: removed_buffer_ids.clone(),
20656                });
20657            }
20658            multi_buffer::Event::ExcerptsEdited {
20659                excerpt_ids,
20660                buffer_ids,
20661            } => {
20662                self.display_map.update(cx, |map, cx| {
20663                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20664                });
20665                cx.emit(EditorEvent::ExcerptsEdited {
20666                    ids: excerpt_ids.clone(),
20667                });
20668            }
20669            multi_buffer::Event::ExcerptsExpanded { ids } => {
20670                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20671                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20672            }
20673            multi_buffer::Event::Reparsed(buffer_id) => {
20674                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20675                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20676
20677                cx.emit(EditorEvent::Reparsed(*buffer_id));
20678            }
20679            multi_buffer::Event::DiffHunksToggled => {
20680                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20681            }
20682            multi_buffer::Event::LanguageChanged(buffer_id) => {
20683                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20684                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20685                cx.emit(EditorEvent::Reparsed(*buffer_id));
20686                cx.notify();
20687            }
20688            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20689            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20690            multi_buffer::Event::FileHandleChanged
20691            | multi_buffer::Event::Reloaded
20692            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20693            multi_buffer::Event::DiagnosticsUpdated => {
20694                self.update_diagnostics_state(window, cx);
20695            }
20696            _ => {}
20697        };
20698    }
20699
20700    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20701        if !self.diagnostics_enabled() {
20702            return;
20703        }
20704        self.refresh_active_diagnostics(cx);
20705        self.refresh_inline_diagnostics(true, window, cx);
20706        self.scrollbar_marker_state.dirty = true;
20707        cx.notify();
20708    }
20709
20710    pub fn start_temporary_diff_override(&mut self) {
20711        self.load_diff_task.take();
20712        self.temporary_diff_override = true;
20713    }
20714
20715    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20716        self.temporary_diff_override = false;
20717        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20718        self.buffer.update(cx, |buffer, cx| {
20719            buffer.set_all_diff_hunks_collapsed(cx);
20720        });
20721
20722        if let Some(project) = self.project.clone() {
20723            self.load_diff_task = Some(
20724                update_uncommitted_diff_for_buffer(
20725                    cx.entity(),
20726                    &project,
20727                    self.buffer.read(cx).all_buffers(),
20728                    self.buffer.clone(),
20729                    cx,
20730                )
20731                .shared(),
20732            );
20733        }
20734    }
20735
20736    fn on_display_map_changed(
20737        &mut self,
20738        _: Entity<DisplayMap>,
20739        _: &mut Window,
20740        cx: &mut Context<Self>,
20741    ) {
20742        cx.notify();
20743    }
20744
20745    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20746        if self.diagnostics_enabled() {
20747            let new_severity = EditorSettings::get_global(cx)
20748                .diagnostics_max_severity
20749                .unwrap_or(DiagnosticSeverity::Hint);
20750            self.set_max_diagnostics_severity(new_severity, cx);
20751        }
20752        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20753        self.update_edit_prediction_settings(cx);
20754        self.refresh_edit_prediction(true, false, window, cx);
20755        self.refresh_inline_values(cx);
20756        self.refresh_inlay_hints(
20757            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20758                self.selections.newest_anchor().head(),
20759                &self.buffer.read(cx).snapshot(cx),
20760                cx,
20761            )),
20762            cx,
20763        );
20764
20765        let old_cursor_shape = self.cursor_shape;
20766        let old_show_breadcrumbs = self.show_breadcrumbs;
20767
20768        {
20769            let editor_settings = EditorSettings::get_global(cx);
20770            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20771            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20772            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20773            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20774        }
20775
20776        if old_cursor_shape != self.cursor_shape {
20777            cx.emit(EditorEvent::CursorShapeChanged);
20778        }
20779
20780        if old_show_breadcrumbs != self.show_breadcrumbs {
20781            cx.emit(EditorEvent::BreadcrumbsChanged);
20782        }
20783
20784        let project_settings = ProjectSettings::get_global(cx);
20785        self.serialize_dirty_buffers =
20786            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20787
20788        if self.mode.is_full() {
20789            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20790            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
20791            if self.show_inline_diagnostics != show_inline_diagnostics {
20792                self.show_inline_diagnostics = show_inline_diagnostics;
20793                self.refresh_inline_diagnostics(false, window, cx);
20794            }
20795
20796            if self.git_blame_inline_enabled != inline_blame_enabled {
20797                self.toggle_git_blame_inline_internal(false, window, cx);
20798            }
20799
20800            let minimap_settings = EditorSettings::get_global(cx).minimap;
20801            if self.minimap_visibility != MinimapVisibility::Disabled {
20802                if self.minimap_visibility.settings_visibility()
20803                    != minimap_settings.minimap_enabled()
20804                {
20805                    self.set_minimap_visibility(
20806                        MinimapVisibility::for_mode(self.mode(), cx),
20807                        window,
20808                        cx,
20809                    );
20810                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20811                    minimap_entity.update(cx, |minimap_editor, cx| {
20812                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20813                    })
20814                }
20815            }
20816        }
20817
20818        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20819            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20820        }) {
20821            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20822                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20823            }
20824            self.refresh_colors(false, None, window, cx);
20825        }
20826
20827        cx.notify();
20828    }
20829
20830    pub fn set_searchable(&mut self, searchable: bool) {
20831        self.searchable = searchable;
20832    }
20833
20834    pub fn searchable(&self) -> bool {
20835        self.searchable
20836    }
20837
20838    fn open_proposed_changes_editor(
20839        &mut self,
20840        _: &OpenProposedChangesEditor,
20841        window: &mut Window,
20842        cx: &mut Context<Self>,
20843    ) {
20844        let Some(workspace) = self.workspace() else {
20845            cx.propagate();
20846            return;
20847        };
20848
20849        let selections = self.selections.all::<usize>(cx);
20850        let multi_buffer = self.buffer.read(cx);
20851        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20852        let mut new_selections_by_buffer = HashMap::default();
20853        for selection in selections {
20854            for (buffer, range, _) in
20855                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20856            {
20857                let mut range = range.to_point(buffer);
20858                range.start.column = 0;
20859                range.end.column = buffer.line_len(range.end.row);
20860                new_selections_by_buffer
20861                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20862                    .or_insert(Vec::new())
20863                    .push(range)
20864            }
20865        }
20866
20867        let proposed_changes_buffers = new_selections_by_buffer
20868            .into_iter()
20869            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20870            .collect::<Vec<_>>();
20871        let proposed_changes_editor = cx.new(|cx| {
20872            ProposedChangesEditor::new(
20873                "Proposed changes",
20874                proposed_changes_buffers,
20875                self.project.clone(),
20876                window,
20877                cx,
20878            )
20879        });
20880
20881        window.defer(cx, move |window, cx| {
20882            workspace.update(cx, |workspace, cx| {
20883                workspace.active_pane().update(cx, |pane, cx| {
20884                    pane.add_item(
20885                        Box::new(proposed_changes_editor),
20886                        true,
20887                        true,
20888                        None,
20889                        window,
20890                        cx,
20891                    );
20892                });
20893            });
20894        });
20895    }
20896
20897    pub fn open_excerpts_in_split(
20898        &mut self,
20899        _: &OpenExcerptsSplit,
20900        window: &mut Window,
20901        cx: &mut Context<Self>,
20902    ) {
20903        self.open_excerpts_common(None, true, window, cx)
20904    }
20905
20906    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20907        self.open_excerpts_common(None, false, window, cx)
20908    }
20909
20910    fn open_excerpts_common(
20911        &mut self,
20912        jump_data: Option<JumpData>,
20913        split: bool,
20914        window: &mut Window,
20915        cx: &mut Context<Self>,
20916    ) {
20917        let Some(workspace) = self.workspace() else {
20918            cx.propagate();
20919            return;
20920        };
20921
20922        if self.buffer.read(cx).is_singleton() {
20923            cx.propagate();
20924            return;
20925        }
20926
20927        let mut new_selections_by_buffer = HashMap::default();
20928        match &jump_data {
20929            Some(JumpData::MultiBufferPoint {
20930                excerpt_id,
20931                position,
20932                anchor,
20933                line_offset_from_top,
20934            }) => {
20935                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20936                if let Some(buffer) = multi_buffer_snapshot
20937                    .buffer_id_for_excerpt(*excerpt_id)
20938                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20939                {
20940                    let buffer_snapshot = buffer.read(cx).snapshot();
20941                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20942                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20943                    } else {
20944                        buffer_snapshot.clip_point(*position, Bias::Left)
20945                    };
20946                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20947                    new_selections_by_buffer.insert(
20948                        buffer,
20949                        (
20950                            vec![jump_to_offset..jump_to_offset],
20951                            Some(*line_offset_from_top),
20952                        ),
20953                    );
20954                }
20955            }
20956            Some(JumpData::MultiBufferRow {
20957                row,
20958                line_offset_from_top,
20959            }) => {
20960                let point = MultiBufferPoint::new(row.0, 0);
20961                if let Some((buffer, buffer_point, _)) =
20962                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20963                {
20964                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20965                    new_selections_by_buffer
20966                        .entry(buffer)
20967                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20968                        .0
20969                        .push(buffer_offset..buffer_offset)
20970                }
20971            }
20972            None => {
20973                let selections = self.selections.all::<usize>(cx);
20974                let multi_buffer = self.buffer.read(cx);
20975                for selection in selections {
20976                    for (snapshot, range, _, anchor) in multi_buffer
20977                        .snapshot(cx)
20978                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20979                    {
20980                        if let Some(anchor) = anchor {
20981                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20982                            else {
20983                                continue;
20984                            };
20985                            let offset = text::ToOffset::to_offset(
20986                                &anchor.text_anchor,
20987                                &buffer_handle.read(cx).snapshot(),
20988                            );
20989                            let range = offset..offset;
20990                            new_selections_by_buffer
20991                                .entry(buffer_handle)
20992                                .or_insert((Vec::new(), None))
20993                                .0
20994                                .push(range)
20995                        } else {
20996                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20997                            else {
20998                                continue;
20999                            };
21000                            new_selections_by_buffer
21001                                .entry(buffer_handle)
21002                                .or_insert((Vec::new(), None))
21003                                .0
21004                                .push(range)
21005                        }
21006                    }
21007                }
21008            }
21009        }
21010
21011        new_selections_by_buffer
21012            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21013
21014        if new_selections_by_buffer.is_empty() {
21015            return;
21016        }
21017
21018        // We defer the pane interaction because we ourselves are a workspace item
21019        // and activating a new item causes the pane to call a method on us reentrantly,
21020        // which panics if we're on the stack.
21021        window.defer(cx, move |window, cx| {
21022            workspace.update(cx, |workspace, cx| {
21023                let pane = if split {
21024                    workspace.adjacent_pane(window, cx)
21025                } else {
21026                    workspace.active_pane().clone()
21027                };
21028
21029                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21030                    let editor = buffer
21031                        .read(cx)
21032                        .file()
21033                        .is_none()
21034                        .then(|| {
21035                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21036                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21037                            // Instead, we try to activate the existing editor in the pane first.
21038                            let (editor, pane_item_index) =
21039                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21040                                    let editor = item.downcast::<Editor>()?;
21041                                    let singleton_buffer =
21042                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21043                                    if singleton_buffer == buffer {
21044                                        Some((editor, i))
21045                                    } else {
21046                                        None
21047                                    }
21048                                })?;
21049                            pane.update(cx, |pane, cx| {
21050                                pane.activate_item(pane_item_index, true, true, window, cx)
21051                            });
21052                            Some(editor)
21053                        })
21054                        .flatten()
21055                        .unwrap_or_else(|| {
21056                            workspace.open_project_item::<Self>(
21057                                pane.clone(),
21058                                buffer,
21059                                true,
21060                                true,
21061                                window,
21062                                cx,
21063                            )
21064                        });
21065
21066                    editor.update(cx, |editor, cx| {
21067                        let autoscroll = match scroll_offset {
21068                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21069                            None => Autoscroll::newest(),
21070                        };
21071                        let nav_history = editor.nav_history.take();
21072                        editor.change_selections(
21073                            SelectionEffects::scroll(autoscroll),
21074                            window,
21075                            cx,
21076                            |s| {
21077                                s.select_ranges(ranges);
21078                            },
21079                        );
21080                        editor.nav_history = nav_history;
21081                    });
21082                }
21083            })
21084        });
21085    }
21086
21087    // For now, don't allow opening excerpts in buffers that aren't backed by
21088    // regular project files.
21089    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21090        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21091    }
21092
21093    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21094        let snapshot = self.buffer.read(cx).read(cx);
21095        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21096        Some(
21097            ranges
21098                .iter()
21099                .map(move |range| {
21100                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21101                })
21102                .collect(),
21103        )
21104    }
21105
21106    fn selection_replacement_ranges(
21107        &self,
21108        range: Range<OffsetUtf16>,
21109        cx: &mut App,
21110    ) -> Vec<Range<OffsetUtf16>> {
21111        let selections = self.selections.all::<OffsetUtf16>(cx);
21112        let newest_selection = selections
21113            .iter()
21114            .max_by_key(|selection| selection.id)
21115            .unwrap();
21116        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21117        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21118        let snapshot = self.buffer.read(cx).read(cx);
21119        selections
21120            .into_iter()
21121            .map(|mut selection| {
21122                selection.start.0 =
21123                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21124                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21125                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21126                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21127            })
21128            .collect()
21129    }
21130
21131    fn report_editor_event(
21132        &self,
21133        reported_event: ReportEditorEvent,
21134        file_extension: Option<String>,
21135        cx: &App,
21136    ) {
21137        if cfg!(any(test, feature = "test-support")) {
21138            return;
21139        }
21140
21141        let Some(project) = &self.project else { return };
21142
21143        // If None, we are in a file without an extension
21144        let file = self
21145            .buffer
21146            .read(cx)
21147            .as_singleton()
21148            .and_then(|b| b.read(cx).file());
21149        let file_extension = file_extension.or(file
21150            .as_ref()
21151            .and_then(|file| Path::new(file.file_name(cx)).extension())
21152            .and_then(|e| e.to_str())
21153            .map(|a| a.to_string()));
21154
21155        let vim_mode = vim_enabled(cx);
21156
21157        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21158        let copilot_enabled = edit_predictions_provider
21159            == language::language_settings::EditPredictionProvider::Copilot;
21160        let copilot_enabled_for_language = self
21161            .buffer
21162            .read(cx)
21163            .language_settings(cx)
21164            .show_edit_predictions;
21165
21166        let project = project.read(cx);
21167        let event_type = reported_event.event_type();
21168
21169        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21170            telemetry::event!(
21171                event_type,
21172                type = if auto_saved {"autosave"} else {"manual"},
21173                file_extension,
21174                vim_mode,
21175                copilot_enabled,
21176                copilot_enabled_for_language,
21177                edit_predictions_provider,
21178                is_via_ssh = project.is_via_remote_server(),
21179            );
21180        } else {
21181            telemetry::event!(
21182                event_type,
21183                file_extension,
21184                vim_mode,
21185                copilot_enabled,
21186                copilot_enabled_for_language,
21187                edit_predictions_provider,
21188                is_via_ssh = project.is_via_remote_server(),
21189            );
21190        };
21191    }
21192
21193    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21194    /// with each line being an array of {text, highlight} objects.
21195    fn copy_highlight_json(
21196        &mut self,
21197        _: &CopyHighlightJson,
21198        window: &mut Window,
21199        cx: &mut Context<Self>,
21200    ) {
21201        #[derive(Serialize)]
21202        struct Chunk<'a> {
21203            text: String,
21204            highlight: Option<&'a str>,
21205        }
21206
21207        let snapshot = self.buffer.read(cx).snapshot(cx);
21208        let range = self
21209            .selected_text_range(false, window, cx)
21210            .and_then(|selection| {
21211                if selection.range.is_empty() {
21212                    None
21213                } else {
21214                    Some(selection.range)
21215                }
21216            })
21217            .unwrap_or_else(|| 0..snapshot.len());
21218
21219        let chunks = snapshot.chunks(range, true);
21220        let mut lines = Vec::new();
21221        let mut line: VecDeque<Chunk> = VecDeque::new();
21222
21223        let Some(style) = self.style.as_ref() else {
21224            return;
21225        };
21226
21227        for chunk in chunks {
21228            let highlight = chunk
21229                .syntax_highlight_id
21230                .and_then(|id| id.name(&style.syntax));
21231            let mut chunk_lines = chunk.text.split('\n').peekable();
21232            while let Some(text) = chunk_lines.next() {
21233                let mut merged_with_last_token = false;
21234                if let Some(last_token) = line.back_mut()
21235                    && last_token.highlight == highlight
21236                {
21237                    last_token.text.push_str(text);
21238                    merged_with_last_token = true;
21239                }
21240
21241                if !merged_with_last_token {
21242                    line.push_back(Chunk {
21243                        text: text.into(),
21244                        highlight,
21245                    });
21246                }
21247
21248                if chunk_lines.peek().is_some() {
21249                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21250                        line.pop_front();
21251                    }
21252                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21253                        line.pop_back();
21254                    }
21255
21256                    lines.push(mem::take(&mut line));
21257                }
21258            }
21259        }
21260
21261        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21262            return;
21263        };
21264        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21265    }
21266
21267    pub fn open_context_menu(
21268        &mut self,
21269        _: &OpenContextMenu,
21270        window: &mut Window,
21271        cx: &mut Context<Self>,
21272    ) {
21273        self.request_autoscroll(Autoscroll::newest(), cx);
21274        let position = self.selections.newest_display(cx).start;
21275        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21276    }
21277
21278    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21279        &self.inlay_hint_cache
21280    }
21281
21282    pub fn replay_insert_event(
21283        &mut self,
21284        text: &str,
21285        relative_utf16_range: Option<Range<isize>>,
21286        window: &mut Window,
21287        cx: &mut Context<Self>,
21288    ) {
21289        if !self.input_enabled {
21290            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21291            return;
21292        }
21293        if let Some(relative_utf16_range) = relative_utf16_range {
21294            let selections = self.selections.all::<OffsetUtf16>(cx);
21295            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21296                let new_ranges = selections.into_iter().map(|range| {
21297                    let start = OffsetUtf16(
21298                        range
21299                            .head()
21300                            .0
21301                            .saturating_add_signed(relative_utf16_range.start),
21302                    );
21303                    let end = OffsetUtf16(
21304                        range
21305                            .head()
21306                            .0
21307                            .saturating_add_signed(relative_utf16_range.end),
21308                    );
21309                    start..end
21310                });
21311                s.select_ranges(new_ranges);
21312            });
21313        }
21314
21315        self.handle_input(text, window, cx);
21316    }
21317
21318    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21319        let Some(provider) = self.semantics_provider.as_ref() else {
21320            return false;
21321        };
21322
21323        let mut supports = false;
21324        self.buffer().update(cx, |this, cx| {
21325            this.for_each_buffer(|buffer| {
21326                supports |= provider.supports_inlay_hints(buffer, cx);
21327            });
21328        });
21329
21330        supports
21331    }
21332
21333    pub fn is_focused(&self, window: &Window) -> bool {
21334        self.focus_handle.is_focused(window)
21335    }
21336
21337    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21338        cx.emit(EditorEvent::Focused);
21339
21340        if let Some(descendant) = self
21341            .last_focused_descendant
21342            .take()
21343            .and_then(|descendant| descendant.upgrade())
21344        {
21345            window.focus(&descendant);
21346        } else {
21347            if let Some(blame) = self.blame.as_ref() {
21348                blame.update(cx, GitBlame::focus)
21349            }
21350
21351            self.blink_manager.update(cx, BlinkManager::enable);
21352            self.show_cursor_names(window, cx);
21353            self.buffer.update(cx, |buffer, cx| {
21354                buffer.finalize_last_transaction(cx);
21355                if self.leader_id.is_none() {
21356                    buffer.set_active_selections(
21357                        &self.selections.disjoint_anchors_arc(),
21358                        self.selections.line_mode,
21359                        self.cursor_shape,
21360                        cx,
21361                    );
21362                }
21363            });
21364        }
21365    }
21366
21367    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21368        cx.emit(EditorEvent::FocusedIn)
21369    }
21370
21371    fn handle_focus_out(
21372        &mut self,
21373        event: FocusOutEvent,
21374        _window: &mut Window,
21375        cx: &mut Context<Self>,
21376    ) {
21377        if event.blurred != self.focus_handle {
21378            self.last_focused_descendant = Some(event.blurred);
21379        }
21380        self.selection_drag_state = SelectionDragState::None;
21381        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21382    }
21383
21384    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21385        self.blink_manager.update(cx, BlinkManager::disable);
21386        self.buffer
21387            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21388
21389        if let Some(blame) = self.blame.as_ref() {
21390            blame.update(cx, GitBlame::blur)
21391        }
21392        if !self.hover_state.focused(window, cx) {
21393            hide_hover(self, cx);
21394        }
21395        if !self
21396            .context_menu
21397            .borrow()
21398            .as_ref()
21399            .is_some_and(|context_menu| context_menu.focused(window, cx))
21400        {
21401            self.hide_context_menu(window, cx);
21402        }
21403        self.discard_edit_prediction(false, cx);
21404        cx.emit(EditorEvent::Blurred);
21405        cx.notify();
21406    }
21407
21408    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21409        let mut pending: String = window
21410            .pending_input_keystrokes()
21411            .into_iter()
21412            .flatten()
21413            .filter_map(|keystroke| {
21414                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21415                    keystroke.key_char.clone()
21416                } else {
21417                    None
21418                }
21419            })
21420            .collect();
21421
21422        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21423            pending = "".to_string();
21424        }
21425
21426        let existing_pending = self
21427            .text_highlights::<PendingInput>(cx)
21428            .map(|(_, ranges)| ranges.to_vec());
21429        if existing_pending.is_none() && pending.is_empty() {
21430            return;
21431        }
21432        let transaction =
21433            self.transact(window, cx, |this, window, cx| {
21434                let selections = this.selections.all::<usize>(cx);
21435                let edits = selections
21436                    .iter()
21437                    .map(|selection| (selection.end..selection.end, pending.clone()));
21438                this.edit(edits, cx);
21439                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21440                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21441                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21442                    }));
21443                });
21444                if let Some(existing_ranges) = existing_pending {
21445                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21446                    this.edit(edits, cx);
21447                }
21448            });
21449
21450        let snapshot = self.snapshot(window, cx);
21451        let ranges = self
21452            .selections
21453            .all::<usize>(cx)
21454            .into_iter()
21455            .map(|selection| {
21456                snapshot.buffer_snapshot.anchor_after(selection.end)
21457                    ..snapshot
21458                        .buffer_snapshot
21459                        .anchor_before(selection.end + pending.len())
21460            })
21461            .collect();
21462
21463        if pending.is_empty() {
21464            self.clear_highlights::<PendingInput>(cx);
21465        } else {
21466            self.highlight_text::<PendingInput>(
21467                ranges,
21468                HighlightStyle {
21469                    underline: Some(UnderlineStyle {
21470                        thickness: px(1.),
21471                        color: None,
21472                        wavy: false,
21473                    }),
21474                    ..Default::default()
21475                },
21476                cx,
21477            );
21478        }
21479
21480        self.ime_transaction = self.ime_transaction.or(transaction);
21481        if let Some(transaction) = self.ime_transaction {
21482            self.buffer.update(cx, |buffer, cx| {
21483                buffer.group_until_transaction(transaction, cx);
21484            });
21485        }
21486
21487        if self.text_highlights::<PendingInput>(cx).is_none() {
21488            self.ime_transaction.take();
21489        }
21490    }
21491
21492    pub fn register_action_renderer(
21493        &mut self,
21494        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21495    ) -> Subscription {
21496        let id = self.next_editor_action_id.post_inc();
21497        self.editor_actions
21498            .borrow_mut()
21499            .insert(id, Box::new(listener));
21500
21501        let editor_actions = self.editor_actions.clone();
21502        Subscription::new(move || {
21503            editor_actions.borrow_mut().remove(&id);
21504        })
21505    }
21506
21507    pub fn register_action<A: Action>(
21508        &mut self,
21509        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21510    ) -> Subscription {
21511        let id = self.next_editor_action_id.post_inc();
21512        let listener = Arc::new(listener);
21513        self.editor_actions.borrow_mut().insert(
21514            id,
21515            Box::new(move |_, window, _| {
21516                let listener = listener.clone();
21517                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21518                    let action = action.downcast_ref().unwrap();
21519                    if phase == DispatchPhase::Bubble {
21520                        listener(action, window, cx)
21521                    }
21522                })
21523            }),
21524        );
21525
21526        let editor_actions = self.editor_actions.clone();
21527        Subscription::new(move || {
21528            editor_actions.borrow_mut().remove(&id);
21529        })
21530    }
21531
21532    pub fn file_header_size(&self) -> u32 {
21533        FILE_HEADER_HEIGHT
21534    }
21535
21536    pub fn restore(
21537        &mut self,
21538        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21539        window: &mut Window,
21540        cx: &mut Context<Self>,
21541    ) {
21542        let workspace = self.workspace();
21543        let project = self.project();
21544        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21545            let mut tasks = Vec::new();
21546            for (buffer_id, changes) in revert_changes {
21547                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21548                    buffer.update(cx, |buffer, cx| {
21549                        buffer.edit(
21550                            changes
21551                                .into_iter()
21552                                .map(|(range, text)| (range, text.to_string())),
21553                            None,
21554                            cx,
21555                        );
21556                    });
21557
21558                    if let Some(project) =
21559                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21560                    {
21561                        project.update(cx, |project, cx| {
21562                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21563                        })
21564                    }
21565                }
21566            }
21567            tasks
21568        });
21569        cx.spawn_in(window, async move |_, cx| {
21570            for (buffer, task) in save_tasks {
21571                let result = task.await;
21572                if result.is_err() {
21573                    let Some(path) = buffer
21574                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21575                        .ok()
21576                    else {
21577                        continue;
21578                    };
21579                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21580                        let Some(task) = cx
21581                            .update_window_entity(workspace, |workspace, window, cx| {
21582                                workspace
21583                                    .open_path_preview(path, None, false, false, false, window, cx)
21584                            })
21585                            .ok()
21586                        else {
21587                            continue;
21588                        };
21589                        task.await.log_err();
21590                    }
21591                }
21592            }
21593        })
21594        .detach();
21595        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21596            selections.refresh()
21597        });
21598    }
21599
21600    pub fn to_pixel_point(
21601        &self,
21602        source: multi_buffer::Anchor,
21603        editor_snapshot: &EditorSnapshot,
21604        window: &mut Window,
21605    ) -> Option<gpui::Point<Pixels>> {
21606        let source_point = source.to_display_point(editor_snapshot);
21607        self.display_to_pixel_point(source_point, editor_snapshot, window)
21608    }
21609
21610    pub fn display_to_pixel_point(
21611        &self,
21612        source: DisplayPoint,
21613        editor_snapshot: &EditorSnapshot,
21614        window: &mut Window,
21615    ) -> Option<gpui::Point<Pixels>> {
21616        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21617        let text_layout_details = self.text_layout_details(window);
21618        let scroll_top = text_layout_details
21619            .scroll_anchor
21620            .scroll_position(editor_snapshot)
21621            .y;
21622
21623        if source.row().as_f32() < scroll_top.floor() {
21624            return None;
21625        }
21626        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21627        let source_y = line_height * (source.row().as_f32() - scroll_top);
21628        Some(gpui::Point::new(source_x, source_y))
21629    }
21630
21631    pub fn has_visible_completions_menu(&self) -> bool {
21632        !self.edit_prediction_preview_is_active()
21633            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21634                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21635            })
21636    }
21637
21638    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21639        if self.mode.is_minimap() {
21640            return;
21641        }
21642        self.addons
21643            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21644    }
21645
21646    pub fn unregister_addon<T: Addon>(&mut self) {
21647        self.addons.remove(&std::any::TypeId::of::<T>());
21648    }
21649
21650    pub fn addon<T: Addon>(&self) -> Option<&T> {
21651        let type_id = std::any::TypeId::of::<T>();
21652        self.addons
21653            .get(&type_id)
21654            .and_then(|item| item.to_any().downcast_ref::<T>())
21655    }
21656
21657    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21658        let type_id = std::any::TypeId::of::<T>();
21659        self.addons
21660            .get_mut(&type_id)
21661            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21662    }
21663
21664    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21665        let text_layout_details = self.text_layout_details(window);
21666        let style = &text_layout_details.editor_style;
21667        let font_id = window.text_system().resolve_font(&style.text.font());
21668        let font_size = style.text.font_size.to_pixels(window.rem_size());
21669        let line_height = style.text.line_height_in_pixels(window.rem_size());
21670        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21671        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21672
21673        CharacterDimensions {
21674            em_width,
21675            em_advance,
21676            line_height,
21677        }
21678    }
21679
21680    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21681        self.load_diff_task.clone()
21682    }
21683
21684    fn read_metadata_from_db(
21685        &mut self,
21686        item_id: u64,
21687        workspace_id: WorkspaceId,
21688        window: &mut Window,
21689        cx: &mut Context<Editor>,
21690    ) {
21691        if self.is_singleton(cx)
21692            && !self.mode.is_minimap()
21693            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21694        {
21695            let buffer_snapshot = OnceCell::new();
21696
21697            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21698                && !folds.is_empty()
21699            {
21700                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21701                self.fold_ranges(
21702                    folds
21703                        .into_iter()
21704                        .map(|(start, end)| {
21705                            snapshot.clip_offset(start, Bias::Left)
21706                                ..snapshot.clip_offset(end, Bias::Right)
21707                        })
21708                        .collect(),
21709                    false,
21710                    window,
21711                    cx,
21712                );
21713            }
21714
21715            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21716                && !selections.is_empty()
21717            {
21718                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21719                // skip adding the initial selection to selection history
21720                self.selection_history.mode = SelectionHistoryMode::Skipping;
21721                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21722                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21723                        snapshot.clip_offset(start, Bias::Left)
21724                            ..snapshot.clip_offset(end, Bias::Right)
21725                    }));
21726                });
21727                self.selection_history.mode = SelectionHistoryMode::Normal;
21728            };
21729        }
21730
21731        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21732    }
21733
21734    fn update_lsp_data(
21735        &mut self,
21736        ignore_cache: bool,
21737        for_buffer: Option<BufferId>,
21738        window: &mut Window,
21739        cx: &mut Context<'_, Self>,
21740    ) {
21741        self.pull_diagnostics(for_buffer, window, cx);
21742        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21743    }
21744}
21745
21746fn edit_for_markdown_paste<'a>(
21747    buffer: &MultiBufferSnapshot,
21748    range: Range<usize>,
21749    to_insert: &'a str,
21750    url: Option<url::Url>,
21751) -> (Range<usize>, Cow<'a, str>) {
21752    if url.is_none() {
21753        return (range, Cow::Borrowed(to_insert));
21754    };
21755
21756    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
21757
21758    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
21759        Cow::Borrowed(to_insert)
21760    } else {
21761        Cow::Owned(format!("[{old_text}]({to_insert})"))
21762    };
21763    (range, new_text)
21764}
21765
21766fn vim_enabled(cx: &App) -> bool {
21767    vim_mode_setting::VimModeSetting::try_get(cx)
21768        .map(|vim_mode| vim_mode.0)
21769        .unwrap_or(false)
21770}
21771
21772fn process_completion_for_edit(
21773    completion: &Completion,
21774    intent: CompletionIntent,
21775    buffer: &Entity<Buffer>,
21776    cursor_position: &text::Anchor,
21777    cx: &mut Context<Editor>,
21778) -> CompletionEdit {
21779    let buffer = buffer.read(cx);
21780    let buffer_snapshot = buffer.snapshot();
21781    let (snippet, new_text) = if completion.is_snippet() {
21782        // Workaround for typescript language server issues so that methods don't expand within
21783        // strings and functions with type expressions. The previous point is used because the query
21784        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21785        let mut snippet_source = completion.new_text.clone();
21786        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21787        previous_point.column = previous_point.column.saturating_sub(1);
21788        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21789            && scope.prefers_label_for_snippet_in_completion()
21790            && let Some(label) = completion.label()
21791            && matches!(
21792                completion.kind(),
21793                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21794            )
21795        {
21796            snippet_source = label;
21797        }
21798        match Snippet::parse(&snippet_source).log_err() {
21799            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21800            None => (None, completion.new_text.clone()),
21801        }
21802    } else {
21803        (None, completion.new_text.clone())
21804    };
21805
21806    let mut range_to_replace = {
21807        let replace_range = &completion.replace_range;
21808        if let CompletionSource::Lsp {
21809            insert_range: Some(insert_range),
21810            ..
21811        } = &completion.source
21812        {
21813            debug_assert_eq!(
21814                insert_range.start, replace_range.start,
21815                "insert_range and replace_range should start at the same position"
21816            );
21817            debug_assert!(
21818                insert_range
21819                    .start
21820                    .cmp(cursor_position, &buffer_snapshot)
21821                    .is_le(),
21822                "insert_range should start before or at cursor position"
21823            );
21824            debug_assert!(
21825                replace_range
21826                    .start
21827                    .cmp(cursor_position, &buffer_snapshot)
21828                    .is_le(),
21829                "replace_range should start before or at cursor position"
21830            );
21831
21832            let should_replace = match intent {
21833                CompletionIntent::CompleteWithInsert => false,
21834                CompletionIntent::CompleteWithReplace => true,
21835                CompletionIntent::Complete | CompletionIntent::Compose => {
21836                    let insert_mode =
21837                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21838                            .completions
21839                            .lsp_insert_mode;
21840                    match insert_mode {
21841                        LspInsertMode::Insert => false,
21842                        LspInsertMode::Replace => true,
21843                        LspInsertMode::ReplaceSubsequence => {
21844                            let mut text_to_replace = buffer.chars_for_range(
21845                                buffer.anchor_before(replace_range.start)
21846                                    ..buffer.anchor_after(replace_range.end),
21847                            );
21848                            let mut current_needle = text_to_replace.next();
21849                            for haystack_ch in completion.label.text.chars() {
21850                                if let Some(needle_ch) = current_needle
21851                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21852                                {
21853                                    current_needle = text_to_replace.next();
21854                                }
21855                            }
21856                            current_needle.is_none()
21857                        }
21858                        LspInsertMode::ReplaceSuffix => {
21859                            if replace_range
21860                                .end
21861                                .cmp(cursor_position, &buffer_snapshot)
21862                                .is_gt()
21863                            {
21864                                let range_after_cursor = *cursor_position..replace_range.end;
21865                                let text_after_cursor = buffer
21866                                    .text_for_range(
21867                                        buffer.anchor_before(range_after_cursor.start)
21868                                            ..buffer.anchor_after(range_after_cursor.end),
21869                                    )
21870                                    .collect::<String>()
21871                                    .to_ascii_lowercase();
21872                                completion
21873                                    .label
21874                                    .text
21875                                    .to_ascii_lowercase()
21876                                    .ends_with(&text_after_cursor)
21877                            } else {
21878                                true
21879                            }
21880                        }
21881                    }
21882                }
21883            };
21884
21885            if should_replace {
21886                replace_range.clone()
21887            } else {
21888                insert_range.clone()
21889            }
21890        } else {
21891            replace_range.clone()
21892        }
21893    };
21894
21895    if range_to_replace
21896        .end
21897        .cmp(cursor_position, &buffer_snapshot)
21898        .is_lt()
21899    {
21900        range_to_replace.end = *cursor_position;
21901    }
21902
21903    CompletionEdit {
21904        new_text,
21905        replace_range: range_to_replace.to_offset(buffer),
21906        snippet,
21907    }
21908}
21909
21910struct CompletionEdit {
21911    new_text: String,
21912    replace_range: Range<usize>,
21913    snippet: Option<Snippet>,
21914}
21915
21916fn insert_extra_newline_brackets(
21917    buffer: &MultiBufferSnapshot,
21918    range: Range<usize>,
21919    language: &language::LanguageScope,
21920) -> bool {
21921    let leading_whitespace_len = buffer
21922        .reversed_chars_at(range.start)
21923        .take_while(|c| c.is_whitespace() && *c != '\n')
21924        .map(|c| c.len_utf8())
21925        .sum::<usize>();
21926    let trailing_whitespace_len = buffer
21927        .chars_at(range.end)
21928        .take_while(|c| c.is_whitespace() && *c != '\n')
21929        .map(|c| c.len_utf8())
21930        .sum::<usize>();
21931    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21932
21933    language.brackets().any(|(pair, enabled)| {
21934        let pair_start = pair.start.trim_end();
21935        let pair_end = pair.end.trim_start();
21936
21937        enabled
21938            && pair.newline
21939            && buffer.contains_str_at(range.end, pair_end)
21940            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21941    })
21942}
21943
21944fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21945    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21946        [(buffer, range, _)] => (*buffer, range.clone()),
21947        _ => return false,
21948    };
21949    let pair = {
21950        let mut result: Option<BracketMatch> = None;
21951
21952        for pair in buffer
21953            .all_bracket_ranges(range.clone())
21954            .filter(move |pair| {
21955                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21956            })
21957        {
21958            let len = pair.close_range.end - pair.open_range.start;
21959
21960            if let Some(existing) = &result {
21961                let existing_len = existing.close_range.end - existing.open_range.start;
21962                if len > existing_len {
21963                    continue;
21964                }
21965            }
21966
21967            result = Some(pair);
21968        }
21969
21970        result
21971    };
21972    let Some(pair) = pair else {
21973        return false;
21974    };
21975    pair.newline_only
21976        && buffer
21977            .chars_for_range(pair.open_range.end..range.start)
21978            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21979            .all(|c| c.is_whitespace() && c != '\n')
21980}
21981
21982fn update_uncommitted_diff_for_buffer(
21983    editor: Entity<Editor>,
21984    project: &Entity<Project>,
21985    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21986    buffer: Entity<MultiBuffer>,
21987    cx: &mut App,
21988) -> Task<()> {
21989    let mut tasks = Vec::new();
21990    project.update(cx, |project, cx| {
21991        for buffer in buffers {
21992            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21993                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21994            }
21995        }
21996    });
21997    cx.spawn(async move |cx| {
21998        let diffs = future::join_all(tasks).await;
21999        if editor
22000            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22001            .unwrap_or(false)
22002        {
22003            return;
22004        }
22005
22006        buffer
22007            .update(cx, |buffer, cx| {
22008                for diff in diffs.into_iter().flatten() {
22009                    buffer.add_diff(diff, cx);
22010                }
22011            })
22012            .ok();
22013    })
22014}
22015
22016fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22017    let tab_size = tab_size.get() as usize;
22018    let mut width = offset;
22019
22020    for ch in text.chars() {
22021        width += if ch == '\t' {
22022            tab_size - (width % tab_size)
22023        } else {
22024            1
22025        };
22026    }
22027
22028    width - offset
22029}
22030
22031#[cfg(test)]
22032mod tests {
22033    use super::*;
22034
22035    #[test]
22036    fn test_string_size_with_expanded_tabs() {
22037        let nz = |val| NonZeroU32::new(val).unwrap();
22038        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22039        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22040        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22041        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22042        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22043        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22044        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22045        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22046    }
22047}
22048
22049/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22050struct WordBreakingTokenizer<'a> {
22051    input: &'a str,
22052}
22053
22054impl<'a> WordBreakingTokenizer<'a> {
22055    fn new(input: &'a str) -> Self {
22056        Self { input }
22057    }
22058}
22059
22060fn is_char_ideographic(ch: char) -> bool {
22061    use unicode_script::Script::*;
22062    use unicode_script::UnicodeScript;
22063    matches!(ch.script(), Han | Tangut | Yi)
22064}
22065
22066fn is_grapheme_ideographic(text: &str) -> bool {
22067    text.chars().any(is_char_ideographic)
22068}
22069
22070fn is_grapheme_whitespace(text: &str) -> bool {
22071    text.chars().any(|x| x.is_whitespace())
22072}
22073
22074fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22075    text.chars()
22076        .next()
22077        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22078}
22079
22080#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22081enum WordBreakToken<'a> {
22082    Word { token: &'a str, grapheme_len: usize },
22083    InlineWhitespace { token: &'a str, grapheme_len: usize },
22084    Newline,
22085}
22086
22087impl<'a> Iterator for WordBreakingTokenizer<'a> {
22088    /// Yields a span, the count of graphemes in the token, and whether it was
22089    /// whitespace. Note that it also breaks at word boundaries.
22090    type Item = WordBreakToken<'a>;
22091
22092    fn next(&mut self) -> Option<Self::Item> {
22093        use unicode_segmentation::UnicodeSegmentation;
22094        if self.input.is_empty() {
22095            return None;
22096        }
22097
22098        let mut iter = self.input.graphemes(true).peekable();
22099        let mut offset = 0;
22100        let mut grapheme_len = 0;
22101        if let Some(first_grapheme) = iter.next() {
22102            let is_newline = first_grapheme == "\n";
22103            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22104            offset += first_grapheme.len();
22105            grapheme_len += 1;
22106            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22107                if let Some(grapheme) = iter.peek().copied()
22108                    && should_stay_with_preceding_ideograph(grapheme)
22109                {
22110                    offset += grapheme.len();
22111                    grapheme_len += 1;
22112                }
22113            } else {
22114                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22115                let mut next_word_bound = words.peek().copied();
22116                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22117                    next_word_bound = words.next();
22118                }
22119                while let Some(grapheme) = iter.peek().copied() {
22120                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22121                        break;
22122                    };
22123                    if is_grapheme_whitespace(grapheme) != is_whitespace
22124                        || (grapheme == "\n") != is_newline
22125                    {
22126                        break;
22127                    };
22128                    offset += grapheme.len();
22129                    grapheme_len += 1;
22130                    iter.next();
22131                }
22132            }
22133            let token = &self.input[..offset];
22134            self.input = &self.input[offset..];
22135            if token == "\n" {
22136                Some(WordBreakToken::Newline)
22137            } else if is_whitespace {
22138                Some(WordBreakToken::InlineWhitespace {
22139                    token,
22140                    grapheme_len,
22141                })
22142            } else {
22143                Some(WordBreakToken::Word {
22144                    token,
22145                    grapheme_len,
22146                })
22147            }
22148        } else {
22149            None
22150        }
22151    }
22152}
22153
22154#[test]
22155fn test_word_breaking_tokenizer() {
22156    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22157        ("", &[]),
22158        ("  ", &[whitespace("  ", 2)]),
22159        ("Ʒ", &[word("Ʒ", 1)]),
22160        ("Ǽ", &[word("Ǽ", 1)]),
22161        ("", &[word("", 1)]),
22162        ("⋑⋑", &[word("⋑⋑", 2)]),
22163        (
22164            "原理,进而",
22165            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22166        ),
22167        (
22168            "hello world",
22169            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22170        ),
22171        (
22172            "hello, world",
22173            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22174        ),
22175        (
22176            "  hello world",
22177            &[
22178                whitespace("  ", 2),
22179                word("hello", 5),
22180                whitespace(" ", 1),
22181                word("world", 5),
22182            ],
22183        ),
22184        (
22185            "这是什么 \n 钢笔",
22186            &[
22187                word("", 1),
22188                word("", 1),
22189                word("", 1),
22190                word("", 1),
22191                whitespace(" ", 1),
22192                newline(),
22193                whitespace(" ", 1),
22194                word("", 1),
22195                word("", 1),
22196            ],
22197        ),
22198        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22199    ];
22200
22201    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22202        WordBreakToken::Word {
22203            token,
22204            grapheme_len,
22205        }
22206    }
22207
22208    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22209        WordBreakToken::InlineWhitespace {
22210            token,
22211            grapheme_len,
22212        }
22213    }
22214
22215    fn newline() -> WordBreakToken<'static> {
22216        WordBreakToken::Newline
22217    }
22218
22219    for (input, result) in tests {
22220        assert_eq!(
22221            WordBreakingTokenizer::new(input)
22222                .collect::<Vec<_>>()
22223                .as_slice(),
22224            *result,
22225        );
22226    }
22227}
22228
22229fn wrap_with_prefix(
22230    first_line_prefix: String,
22231    subsequent_lines_prefix: String,
22232    unwrapped_text: String,
22233    wrap_column: usize,
22234    tab_size: NonZeroU32,
22235    preserve_existing_whitespace: bool,
22236) -> String {
22237    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22238    let subsequent_lines_prefix_len =
22239        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22240    let mut wrapped_text = String::new();
22241    let mut current_line = first_line_prefix;
22242    let mut is_first_line = true;
22243
22244    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22245    let mut current_line_len = first_line_prefix_len;
22246    let mut in_whitespace = false;
22247    for token in tokenizer {
22248        let have_preceding_whitespace = in_whitespace;
22249        match token {
22250            WordBreakToken::Word {
22251                token,
22252                grapheme_len,
22253            } => {
22254                in_whitespace = false;
22255                let current_prefix_len = if is_first_line {
22256                    first_line_prefix_len
22257                } else {
22258                    subsequent_lines_prefix_len
22259                };
22260                if current_line_len + grapheme_len > wrap_column
22261                    && current_line_len != current_prefix_len
22262                {
22263                    wrapped_text.push_str(current_line.trim_end());
22264                    wrapped_text.push('\n');
22265                    is_first_line = false;
22266                    current_line = subsequent_lines_prefix.clone();
22267                    current_line_len = subsequent_lines_prefix_len;
22268                }
22269                current_line.push_str(token);
22270                current_line_len += grapheme_len;
22271            }
22272            WordBreakToken::InlineWhitespace {
22273                mut token,
22274                mut grapheme_len,
22275            } => {
22276                in_whitespace = true;
22277                if have_preceding_whitespace && !preserve_existing_whitespace {
22278                    continue;
22279                }
22280                if !preserve_existing_whitespace {
22281                    token = " ";
22282                    grapheme_len = 1;
22283                }
22284                let current_prefix_len = if is_first_line {
22285                    first_line_prefix_len
22286                } else {
22287                    subsequent_lines_prefix_len
22288                };
22289                if current_line_len + grapheme_len > wrap_column {
22290                    wrapped_text.push_str(current_line.trim_end());
22291                    wrapped_text.push('\n');
22292                    is_first_line = false;
22293                    current_line = subsequent_lines_prefix.clone();
22294                    current_line_len = subsequent_lines_prefix_len;
22295                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22296                    current_line.push_str(token);
22297                    current_line_len += grapheme_len;
22298                }
22299            }
22300            WordBreakToken::Newline => {
22301                in_whitespace = true;
22302                let current_prefix_len = if is_first_line {
22303                    first_line_prefix_len
22304                } else {
22305                    subsequent_lines_prefix_len
22306                };
22307                if preserve_existing_whitespace {
22308                    wrapped_text.push_str(current_line.trim_end());
22309                    wrapped_text.push('\n');
22310                    is_first_line = false;
22311                    current_line = subsequent_lines_prefix.clone();
22312                    current_line_len = subsequent_lines_prefix_len;
22313                } else if have_preceding_whitespace {
22314                    continue;
22315                } else if current_line_len + 1 > wrap_column
22316                    && current_line_len != current_prefix_len
22317                {
22318                    wrapped_text.push_str(current_line.trim_end());
22319                    wrapped_text.push('\n');
22320                    is_first_line = false;
22321                    current_line = subsequent_lines_prefix.clone();
22322                    current_line_len = subsequent_lines_prefix_len;
22323                } else if current_line_len != current_prefix_len {
22324                    current_line.push(' ');
22325                    current_line_len += 1;
22326                }
22327            }
22328        }
22329    }
22330
22331    if !current_line.is_empty() {
22332        wrapped_text.push_str(&current_line);
22333    }
22334    wrapped_text
22335}
22336
22337#[test]
22338fn test_wrap_with_prefix() {
22339    assert_eq!(
22340        wrap_with_prefix(
22341            "# ".to_string(),
22342            "# ".to_string(),
22343            "abcdefg".to_string(),
22344            4,
22345            NonZeroU32::new(4).unwrap(),
22346            false,
22347        ),
22348        "# abcdefg"
22349    );
22350    assert_eq!(
22351        wrap_with_prefix(
22352            "".to_string(),
22353            "".to_string(),
22354            "\thello world".to_string(),
22355            8,
22356            NonZeroU32::new(4).unwrap(),
22357            false,
22358        ),
22359        "hello\nworld"
22360    );
22361    assert_eq!(
22362        wrap_with_prefix(
22363            "// ".to_string(),
22364            "// ".to_string(),
22365            "xx \nyy zz aa bb cc".to_string(),
22366            12,
22367            NonZeroU32::new(4).unwrap(),
22368            false,
22369        ),
22370        "// xx yy zz\n// aa bb cc"
22371    );
22372    assert_eq!(
22373        wrap_with_prefix(
22374            String::new(),
22375            String::new(),
22376            "这是什么 \n 钢笔".to_string(),
22377            3,
22378            NonZeroU32::new(4).unwrap(),
22379            false,
22380        ),
22381        "这是什\n么 钢\n"
22382    );
22383}
22384
22385pub trait CollaborationHub {
22386    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22387    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22388    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22389}
22390
22391impl CollaborationHub for Entity<Project> {
22392    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22393        self.read(cx).collaborators()
22394    }
22395
22396    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22397        self.read(cx).user_store().read(cx).participant_indices()
22398    }
22399
22400    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22401        let this = self.read(cx);
22402        let user_ids = this.collaborators().values().map(|c| c.user_id);
22403        this.user_store().read(cx).participant_names(user_ids, cx)
22404    }
22405}
22406
22407pub trait SemanticsProvider {
22408    fn hover(
22409        &self,
22410        buffer: &Entity<Buffer>,
22411        position: text::Anchor,
22412        cx: &mut App,
22413    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22414
22415    fn inline_values(
22416        &self,
22417        buffer_handle: Entity<Buffer>,
22418        range: Range<text::Anchor>,
22419        cx: &mut App,
22420    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22421
22422    fn inlay_hints(
22423        &self,
22424        buffer_handle: Entity<Buffer>,
22425        range: Range<text::Anchor>,
22426        cx: &mut App,
22427    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22428
22429    fn resolve_inlay_hint(
22430        &self,
22431        hint: InlayHint,
22432        buffer_handle: Entity<Buffer>,
22433        server_id: LanguageServerId,
22434        cx: &mut App,
22435    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22436
22437    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22438
22439    fn document_highlights(
22440        &self,
22441        buffer: &Entity<Buffer>,
22442        position: text::Anchor,
22443        cx: &mut App,
22444    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22445
22446    fn definitions(
22447        &self,
22448        buffer: &Entity<Buffer>,
22449        position: text::Anchor,
22450        kind: GotoDefinitionKind,
22451        cx: &mut App,
22452    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22453
22454    fn range_for_rename(
22455        &self,
22456        buffer: &Entity<Buffer>,
22457        position: text::Anchor,
22458        cx: &mut App,
22459    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22460
22461    fn perform_rename(
22462        &self,
22463        buffer: &Entity<Buffer>,
22464        position: text::Anchor,
22465        new_name: String,
22466        cx: &mut App,
22467    ) -> Option<Task<Result<ProjectTransaction>>>;
22468}
22469
22470pub trait CompletionProvider {
22471    fn completions(
22472        &self,
22473        excerpt_id: ExcerptId,
22474        buffer: &Entity<Buffer>,
22475        buffer_position: text::Anchor,
22476        trigger: CompletionContext,
22477        window: &mut Window,
22478        cx: &mut Context<Editor>,
22479    ) -> Task<Result<Vec<CompletionResponse>>>;
22480
22481    fn resolve_completions(
22482        &self,
22483        _buffer: Entity<Buffer>,
22484        _completion_indices: Vec<usize>,
22485        _completions: Rc<RefCell<Box<[Completion]>>>,
22486        _cx: &mut Context<Editor>,
22487    ) -> Task<Result<bool>> {
22488        Task::ready(Ok(false))
22489    }
22490
22491    fn apply_additional_edits_for_completion(
22492        &self,
22493        _buffer: Entity<Buffer>,
22494        _completions: Rc<RefCell<Box<[Completion]>>>,
22495        _completion_index: usize,
22496        _push_to_history: bool,
22497        _cx: &mut Context<Editor>,
22498    ) -> Task<Result<Option<language::Transaction>>> {
22499        Task::ready(Ok(None))
22500    }
22501
22502    fn is_completion_trigger(
22503        &self,
22504        buffer: &Entity<Buffer>,
22505        position: language::Anchor,
22506        text: &str,
22507        trigger_in_words: bool,
22508        menu_is_open: bool,
22509        cx: &mut Context<Editor>,
22510    ) -> bool;
22511
22512    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22513
22514    fn sort_completions(&self) -> bool {
22515        true
22516    }
22517
22518    fn filter_completions(&self) -> bool {
22519        true
22520    }
22521}
22522
22523pub trait CodeActionProvider {
22524    fn id(&self) -> Arc<str>;
22525
22526    fn code_actions(
22527        &self,
22528        buffer: &Entity<Buffer>,
22529        range: Range<text::Anchor>,
22530        window: &mut Window,
22531        cx: &mut App,
22532    ) -> Task<Result<Vec<CodeAction>>>;
22533
22534    fn apply_code_action(
22535        &self,
22536        buffer_handle: Entity<Buffer>,
22537        action: CodeAction,
22538        excerpt_id: ExcerptId,
22539        push_to_history: bool,
22540        window: &mut Window,
22541        cx: &mut App,
22542    ) -> Task<Result<ProjectTransaction>>;
22543}
22544
22545impl CodeActionProvider for Entity<Project> {
22546    fn id(&self) -> Arc<str> {
22547        "project".into()
22548    }
22549
22550    fn code_actions(
22551        &self,
22552        buffer: &Entity<Buffer>,
22553        range: Range<text::Anchor>,
22554        _window: &mut Window,
22555        cx: &mut App,
22556    ) -> Task<Result<Vec<CodeAction>>> {
22557        self.update(cx, |project, cx| {
22558            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22559            let code_actions = project.code_actions(buffer, range, None, cx);
22560            cx.background_spawn(async move {
22561                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22562                Ok(code_lens_actions
22563                    .context("code lens fetch")?
22564                    .into_iter()
22565                    .flatten()
22566                    .chain(
22567                        code_actions
22568                            .context("code action fetch")?
22569                            .into_iter()
22570                            .flatten(),
22571                    )
22572                    .collect())
22573            })
22574        })
22575    }
22576
22577    fn apply_code_action(
22578        &self,
22579        buffer_handle: Entity<Buffer>,
22580        action: CodeAction,
22581        _excerpt_id: ExcerptId,
22582        push_to_history: bool,
22583        _window: &mut Window,
22584        cx: &mut App,
22585    ) -> Task<Result<ProjectTransaction>> {
22586        self.update(cx, |project, cx| {
22587            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22588        })
22589    }
22590}
22591
22592fn snippet_completions(
22593    project: &Project,
22594    buffer: &Entity<Buffer>,
22595    buffer_position: text::Anchor,
22596    cx: &mut App,
22597) -> Task<Result<CompletionResponse>> {
22598    let languages = buffer.read(cx).languages_at(buffer_position);
22599    let snippet_store = project.snippets().read(cx);
22600
22601    let scopes: Vec<_> = languages
22602        .iter()
22603        .filter_map(|language| {
22604            let language_name = language.lsp_id();
22605            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22606
22607            if snippets.is_empty() {
22608                None
22609            } else {
22610                Some((language.default_scope(), snippets))
22611            }
22612        })
22613        .collect();
22614
22615    if scopes.is_empty() {
22616        return Task::ready(Ok(CompletionResponse {
22617            completions: vec![],
22618            display_options: CompletionDisplayOptions::default(),
22619            is_incomplete: false,
22620        }));
22621    }
22622
22623    let snapshot = buffer.read(cx).text_snapshot();
22624    let chars: String = snapshot
22625        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22626        .collect();
22627    let executor = cx.background_executor().clone();
22628
22629    cx.background_spawn(async move {
22630        let mut is_incomplete = false;
22631        let mut completions: Vec<Completion> = Vec::new();
22632        for (scope, snippets) in scopes.into_iter() {
22633            let classifier =
22634                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22635            let mut last_word = chars
22636                .chars()
22637                .take_while(|c| classifier.is_word(*c))
22638                .collect::<String>();
22639            last_word = last_word.chars().rev().collect();
22640
22641            if last_word.is_empty() {
22642                return Ok(CompletionResponse {
22643                    completions: vec![],
22644                    display_options: CompletionDisplayOptions::default(),
22645                    is_incomplete: true,
22646                });
22647            }
22648
22649            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22650            let to_lsp = |point: &text::Anchor| {
22651                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22652                point_to_lsp(end)
22653            };
22654            let lsp_end = to_lsp(&buffer_position);
22655
22656            let candidates = snippets
22657                .iter()
22658                .enumerate()
22659                .flat_map(|(ix, snippet)| {
22660                    snippet
22661                        .prefix
22662                        .iter()
22663                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22664                })
22665                .collect::<Vec<StringMatchCandidate>>();
22666
22667            const MAX_RESULTS: usize = 100;
22668            let mut matches = fuzzy::match_strings(
22669                &candidates,
22670                &last_word,
22671                last_word.chars().any(|c| c.is_uppercase()),
22672                true,
22673                MAX_RESULTS,
22674                &Default::default(),
22675                executor.clone(),
22676            )
22677            .await;
22678
22679            if matches.len() >= MAX_RESULTS {
22680                is_incomplete = true;
22681            }
22682
22683            // Remove all candidates where the query's start does not match the start of any word in the candidate
22684            if let Some(query_start) = last_word.chars().next() {
22685                matches.retain(|string_match| {
22686                    split_words(&string_match.string).any(|word| {
22687                        // Check that the first codepoint of the word as lowercase matches the first
22688                        // codepoint of the query as lowercase
22689                        word.chars()
22690                            .flat_map(|codepoint| codepoint.to_lowercase())
22691                            .zip(query_start.to_lowercase())
22692                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22693                    })
22694                });
22695            }
22696
22697            let matched_strings = matches
22698                .into_iter()
22699                .map(|m| m.string)
22700                .collect::<HashSet<_>>();
22701
22702            completions.extend(snippets.iter().filter_map(|snippet| {
22703                let matching_prefix = snippet
22704                    .prefix
22705                    .iter()
22706                    .find(|prefix| matched_strings.contains(*prefix))?;
22707                let start = as_offset - last_word.len();
22708                let start = snapshot.anchor_before(start);
22709                let range = start..buffer_position;
22710                let lsp_start = to_lsp(&start);
22711                let lsp_range = lsp::Range {
22712                    start: lsp_start,
22713                    end: lsp_end,
22714                };
22715                Some(Completion {
22716                    replace_range: range,
22717                    new_text: snippet.body.clone(),
22718                    source: CompletionSource::Lsp {
22719                        insert_range: None,
22720                        server_id: LanguageServerId(usize::MAX),
22721                        resolved: true,
22722                        lsp_completion: Box::new(lsp::CompletionItem {
22723                            label: snippet.prefix.first().unwrap().clone(),
22724                            kind: Some(CompletionItemKind::SNIPPET),
22725                            label_details: snippet.description.as_ref().map(|description| {
22726                                lsp::CompletionItemLabelDetails {
22727                                    detail: Some(description.clone()),
22728                                    description: None,
22729                                }
22730                            }),
22731                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22732                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22733                                lsp::InsertReplaceEdit {
22734                                    new_text: snippet.body.clone(),
22735                                    insert: lsp_range,
22736                                    replace: lsp_range,
22737                                },
22738                            )),
22739                            filter_text: Some(snippet.body.clone()),
22740                            sort_text: Some(char::MAX.to_string()),
22741                            ..lsp::CompletionItem::default()
22742                        }),
22743                        lsp_defaults: None,
22744                    },
22745                    label: CodeLabel {
22746                        text: matching_prefix.clone(),
22747                        runs: Vec::new(),
22748                        filter_range: 0..matching_prefix.len(),
22749                    },
22750                    icon_path: None,
22751                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22752                        single_line: snippet.name.clone().into(),
22753                        plain_text: snippet
22754                            .description
22755                            .clone()
22756                            .map(|description| description.into()),
22757                    }),
22758                    insert_text_mode: None,
22759                    confirm: None,
22760                })
22761            }))
22762        }
22763
22764        Ok(CompletionResponse {
22765            completions,
22766            display_options: CompletionDisplayOptions::default(),
22767            is_incomplete,
22768        })
22769    })
22770}
22771
22772impl CompletionProvider for Entity<Project> {
22773    fn completions(
22774        &self,
22775        _excerpt_id: ExcerptId,
22776        buffer: &Entity<Buffer>,
22777        buffer_position: text::Anchor,
22778        options: CompletionContext,
22779        _window: &mut Window,
22780        cx: &mut Context<Editor>,
22781    ) -> Task<Result<Vec<CompletionResponse>>> {
22782        self.update(cx, |project, cx| {
22783            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22784            let project_completions = project.completions(buffer, buffer_position, options, cx);
22785            cx.background_spawn(async move {
22786                let mut responses = project_completions.await?;
22787                let snippets = snippets.await?;
22788                if !snippets.completions.is_empty() {
22789                    responses.push(snippets);
22790                }
22791                Ok(responses)
22792            })
22793        })
22794    }
22795
22796    fn resolve_completions(
22797        &self,
22798        buffer: Entity<Buffer>,
22799        completion_indices: Vec<usize>,
22800        completions: Rc<RefCell<Box<[Completion]>>>,
22801        cx: &mut Context<Editor>,
22802    ) -> Task<Result<bool>> {
22803        self.update(cx, |project, cx| {
22804            project.lsp_store().update(cx, |lsp_store, cx| {
22805                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22806            })
22807        })
22808    }
22809
22810    fn apply_additional_edits_for_completion(
22811        &self,
22812        buffer: Entity<Buffer>,
22813        completions: Rc<RefCell<Box<[Completion]>>>,
22814        completion_index: usize,
22815        push_to_history: bool,
22816        cx: &mut Context<Editor>,
22817    ) -> Task<Result<Option<language::Transaction>>> {
22818        self.update(cx, |project, cx| {
22819            project.lsp_store().update(cx, |lsp_store, cx| {
22820                lsp_store.apply_additional_edits_for_completion(
22821                    buffer,
22822                    completions,
22823                    completion_index,
22824                    push_to_history,
22825                    cx,
22826                )
22827            })
22828        })
22829    }
22830
22831    fn is_completion_trigger(
22832        &self,
22833        buffer: &Entity<Buffer>,
22834        position: language::Anchor,
22835        text: &str,
22836        trigger_in_words: bool,
22837        menu_is_open: bool,
22838        cx: &mut Context<Editor>,
22839    ) -> bool {
22840        let mut chars = text.chars();
22841        let char = if let Some(char) = chars.next() {
22842            char
22843        } else {
22844            return false;
22845        };
22846        if chars.next().is_some() {
22847            return false;
22848        }
22849
22850        let buffer = buffer.read(cx);
22851        let snapshot = buffer.snapshot();
22852        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22853            return false;
22854        }
22855        let classifier = snapshot
22856            .char_classifier_at(position)
22857            .scope_context(Some(CharScopeContext::Completion));
22858        if trigger_in_words && classifier.is_word(char) {
22859            return true;
22860        }
22861
22862        buffer.completion_triggers().contains(text)
22863    }
22864}
22865
22866impl SemanticsProvider for Entity<Project> {
22867    fn hover(
22868        &self,
22869        buffer: &Entity<Buffer>,
22870        position: text::Anchor,
22871        cx: &mut App,
22872    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22873        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22874    }
22875
22876    fn document_highlights(
22877        &self,
22878        buffer: &Entity<Buffer>,
22879        position: text::Anchor,
22880        cx: &mut App,
22881    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22882        Some(self.update(cx, |project, cx| {
22883            project.document_highlights(buffer, position, cx)
22884        }))
22885    }
22886
22887    fn definitions(
22888        &self,
22889        buffer: &Entity<Buffer>,
22890        position: text::Anchor,
22891        kind: GotoDefinitionKind,
22892        cx: &mut App,
22893    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22894        Some(self.update(cx, |project, cx| match kind {
22895            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22896            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22897            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22898            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22899        }))
22900    }
22901
22902    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22903        self.update(cx, |project, cx| {
22904            if project
22905                .active_debug_session(cx)
22906                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22907            {
22908                return true;
22909            }
22910
22911            buffer.update(cx, |buffer, cx| {
22912                project.any_language_server_supports_inlay_hints(buffer, cx)
22913            })
22914        })
22915    }
22916
22917    fn inline_values(
22918        &self,
22919        buffer_handle: Entity<Buffer>,
22920        range: Range<text::Anchor>,
22921        cx: &mut App,
22922    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22923        self.update(cx, |project, cx| {
22924            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22925
22926            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22927        })
22928    }
22929
22930    fn inlay_hints(
22931        &self,
22932        buffer_handle: Entity<Buffer>,
22933        range: Range<text::Anchor>,
22934        cx: &mut App,
22935    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22936        Some(self.update(cx, |project, cx| {
22937            project.inlay_hints(buffer_handle, range, cx)
22938        }))
22939    }
22940
22941    fn resolve_inlay_hint(
22942        &self,
22943        hint: InlayHint,
22944        buffer_handle: Entity<Buffer>,
22945        server_id: LanguageServerId,
22946        cx: &mut App,
22947    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22948        Some(self.update(cx, |project, cx| {
22949            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22950        }))
22951    }
22952
22953    fn range_for_rename(
22954        &self,
22955        buffer: &Entity<Buffer>,
22956        position: text::Anchor,
22957        cx: &mut App,
22958    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22959        Some(self.update(cx, |project, cx| {
22960            let buffer = buffer.clone();
22961            let task = project.prepare_rename(buffer.clone(), position, cx);
22962            cx.spawn(async move |_, cx| {
22963                Ok(match task.await? {
22964                    PrepareRenameResponse::Success(range) => Some(range),
22965                    PrepareRenameResponse::InvalidPosition => None,
22966                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22967                        // Fallback on using TreeSitter info to determine identifier range
22968                        buffer.read_with(cx, |buffer, _| {
22969                            let snapshot = buffer.snapshot();
22970                            let (range, kind) = snapshot.surrounding_word(position, None);
22971                            if kind != Some(CharKind::Word) {
22972                                return None;
22973                            }
22974                            Some(
22975                                snapshot.anchor_before(range.start)
22976                                    ..snapshot.anchor_after(range.end),
22977                            )
22978                        })?
22979                    }
22980                })
22981            })
22982        }))
22983    }
22984
22985    fn perform_rename(
22986        &self,
22987        buffer: &Entity<Buffer>,
22988        position: text::Anchor,
22989        new_name: String,
22990        cx: &mut App,
22991    ) -> Option<Task<Result<ProjectTransaction>>> {
22992        Some(self.update(cx, |project, cx| {
22993            project.perform_rename(buffer.clone(), position, new_name, cx)
22994        }))
22995    }
22996}
22997
22998fn inlay_hint_settings(
22999    location: Anchor,
23000    snapshot: &MultiBufferSnapshot,
23001    cx: &mut Context<Editor>,
23002) -> InlayHintSettings {
23003    let file = snapshot.file_at(location);
23004    let language = snapshot.language_at(location).map(|l| l.name());
23005    language_settings(language, file, cx).inlay_hints
23006}
23007
23008fn consume_contiguous_rows(
23009    contiguous_row_selections: &mut Vec<Selection<Point>>,
23010    selection: &Selection<Point>,
23011    display_map: &DisplaySnapshot,
23012    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23013) -> (MultiBufferRow, MultiBufferRow) {
23014    contiguous_row_selections.push(selection.clone());
23015    let start_row = starting_row(selection, display_map);
23016    let mut end_row = ending_row(selection, display_map);
23017
23018    while let Some(next_selection) = selections.peek() {
23019        if next_selection.start.row <= end_row.0 {
23020            end_row = ending_row(next_selection, display_map);
23021            contiguous_row_selections.push(selections.next().unwrap().clone());
23022        } else {
23023            break;
23024        }
23025    }
23026    (start_row, end_row)
23027}
23028
23029fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23030    if selection.start.column > 0 {
23031        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23032    } else {
23033        MultiBufferRow(selection.start.row)
23034    }
23035}
23036
23037fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23038    if next_selection.end.column > 0 || next_selection.is_empty() {
23039        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23040    } else {
23041        MultiBufferRow(next_selection.end.row)
23042    }
23043}
23044
23045impl EditorSnapshot {
23046    pub fn remote_selections_in_range<'a>(
23047        &'a self,
23048        range: &'a Range<Anchor>,
23049        collaboration_hub: &dyn CollaborationHub,
23050        cx: &'a App,
23051    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23052        let participant_names = collaboration_hub.user_names(cx);
23053        let participant_indices = collaboration_hub.user_participant_indices(cx);
23054        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23055        let collaborators_by_replica_id = collaborators_by_peer_id
23056            .values()
23057            .map(|collaborator| (collaborator.replica_id, collaborator))
23058            .collect::<HashMap<_, _>>();
23059        self.buffer_snapshot
23060            .selections_in_range(range, false)
23061            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23062                if replica_id == AGENT_REPLICA_ID {
23063                    Some(RemoteSelection {
23064                        replica_id,
23065                        selection,
23066                        cursor_shape,
23067                        line_mode,
23068                        collaborator_id: CollaboratorId::Agent,
23069                        user_name: Some("Agent".into()),
23070                        color: cx.theme().players().agent(),
23071                    })
23072                } else {
23073                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23074                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23075                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23076                    Some(RemoteSelection {
23077                        replica_id,
23078                        selection,
23079                        cursor_shape,
23080                        line_mode,
23081                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23082                        user_name,
23083                        color: if let Some(index) = participant_index {
23084                            cx.theme().players().color_for_participant(index.0)
23085                        } else {
23086                            cx.theme().players().absent()
23087                        },
23088                    })
23089                }
23090            })
23091    }
23092
23093    pub fn hunks_for_ranges(
23094        &self,
23095        ranges: impl IntoIterator<Item = Range<Point>>,
23096    ) -> Vec<MultiBufferDiffHunk> {
23097        let mut hunks = Vec::new();
23098        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23099            HashMap::default();
23100        for query_range in ranges {
23101            let query_rows =
23102                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23103            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23104                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23105            ) {
23106                // Include deleted hunks that are adjacent to the query range, because
23107                // otherwise they would be missed.
23108                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23109                if hunk.status().is_deleted() {
23110                    intersects_range |= hunk.row_range.start == query_rows.end;
23111                    intersects_range |= hunk.row_range.end == query_rows.start;
23112                }
23113                if intersects_range {
23114                    if !processed_buffer_rows
23115                        .entry(hunk.buffer_id)
23116                        .or_default()
23117                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23118                    {
23119                        continue;
23120                    }
23121                    hunks.push(hunk);
23122                }
23123            }
23124        }
23125
23126        hunks
23127    }
23128
23129    fn display_diff_hunks_for_rows<'a>(
23130        &'a self,
23131        display_rows: Range<DisplayRow>,
23132        folded_buffers: &'a HashSet<BufferId>,
23133    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23134        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23135        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23136
23137        self.buffer_snapshot
23138            .diff_hunks_in_range(buffer_start..buffer_end)
23139            .filter_map(|hunk| {
23140                if folded_buffers.contains(&hunk.buffer_id) {
23141                    return None;
23142                }
23143
23144                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23145                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23146
23147                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23148                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23149
23150                let display_hunk = if hunk_display_start.column() != 0 {
23151                    DisplayDiffHunk::Folded {
23152                        display_row: hunk_display_start.row(),
23153                    }
23154                } else {
23155                    let mut end_row = hunk_display_end.row();
23156                    if hunk_display_end.column() > 0 {
23157                        end_row.0 += 1;
23158                    }
23159                    let is_created_file = hunk.is_created_file();
23160                    DisplayDiffHunk::Unfolded {
23161                        status: hunk.status(),
23162                        diff_base_byte_range: hunk.diff_base_byte_range,
23163                        display_row_range: hunk_display_start.row()..end_row,
23164                        multi_buffer_range: Anchor::range_in_buffer(
23165                            hunk.excerpt_id,
23166                            hunk.buffer_id,
23167                            hunk.buffer_range,
23168                        ),
23169                        is_created_file,
23170                    }
23171                };
23172
23173                Some(display_hunk)
23174            })
23175    }
23176
23177    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23178        self.display_snapshot.buffer_snapshot.language_at(position)
23179    }
23180
23181    pub fn is_focused(&self) -> bool {
23182        self.is_focused
23183    }
23184
23185    pub fn placeholder_text(&self) -> Option<String> {
23186        self.placeholder_display_snapshot
23187            .as_ref()
23188            .map(|display_map| display_map.text())
23189    }
23190
23191    pub fn scroll_position(&self) -> gpui::Point<f32> {
23192        self.scroll_anchor.scroll_position(&self.display_snapshot)
23193    }
23194
23195    fn gutter_dimensions(
23196        &self,
23197        font_id: FontId,
23198        font_size: Pixels,
23199        max_line_number_width: Pixels,
23200        cx: &App,
23201    ) -> Option<GutterDimensions> {
23202        if !self.show_gutter {
23203            return None;
23204        }
23205
23206        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23207        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23208
23209        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23210            matches!(
23211                ProjectSettings::get_global(cx).git.git_gutter,
23212                GitGutterSetting::TrackedFiles
23213            )
23214        });
23215        let gutter_settings = EditorSettings::get_global(cx).gutter;
23216        let show_line_numbers = self
23217            .show_line_numbers
23218            .unwrap_or(gutter_settings.line_numbers);
23219        let line_gutter_width = if show_line_numbers {
23220            // Avoid flicker-like gutter resizes when the line number gains another digit by
23221            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23222            let min_width_for_number_on_gutter =
23223                ch_advance * gutter_settings.min_line_number_digits as f32;
23224            max_line_number_width.max(min_width_for_number_on_gutter)
23225        } else {
23226            0.0.into()
23227        };
23228
23229        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23230        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23231
23232        let git_blame_entries_width =
23233            self.git_blame_gutter_max_author_length
23234                .map(|max_author_length| {
23235                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23236                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23237
23238                    /// The number of characters to dedicate to gaps and margins.
23239                    const SPACING_WIDTH: usize = 4;
23240
23241                    let max_char_count = max_author_length.min(renderer.max_author_length())
23242                        + ::git::SHORT_SHA_LENGTH
23243                        + MAX_RELATIVE_TIMESTAMP.len()
23244                        + SPACING_WIDTH;
23245
23246                    ch_advance * max_char_count
23247                });
23248
23249        let is_singleton = self.buffer_snapshot.is_singleton();
23250
23251        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23252        left_padding += if !is_singleton {
23253            ch_width * 4.0
23254        } else if show_runnables || show_breakpoints {
23255            ch_width * 3.0
23256        } else if show_git_gutter && show_line_numbers {
23257            ch_width * 2.0
23258        } else if show_git_gutter || show_line_numbers {
23259            ch_width
23260        } else {
23261            px(0.)
23262        };
23263
23264        let shows_folds = is_singleton && gutter_settings.folds;
23265
23266        let right_padding = if shows_folds && show_line_numbers {
23267            ch_width * 4.0
23268        } else if shows_folds || (!is_singleton && show_line_numbers) {
23269            ch_width * 3.0
23270        } else if show_line_numbers {
23271            ch_width
23272        } else {
23273            px(0.)
23274        };
23275
23276        Some(GutterDimensions {
23277            left_padding,
23278            right_padding,
23279            width: line_gutter_width + left_padding + right_padding,
23280            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23281            git_blame_entries_width,
23282        })
23283    }
23284
23285    pub fn render_crease_toggle(
23286        &self,
23287        buffer_row: MultiBufferRow,
23288        row_contains_cursor: bool,
23289        editor: Entity<Editor>,
23290        window: &mut Window,
23291        cx: &mut App,
23292    ) -> Option<AnyElement> {
23293        let folded = self.is_line_folded(buffer_row);
23294        let mut is_foldable = false;
23295
23296        if let Some(crease) = self
23297            .crease_snapshot
23298            .query_row(buffer_row, &self.buffer_snapshot)
23299        {
23300            is_foldable = true;
23301            match crease {
23302                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23303                    if let Some(render_toggle) = render_toggle {
23304                        let toggle_callback =
23305                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23306                                if folded {
23307                                    editor.update(cx, |editor, cx| {
23308                                        editor.fold_at(buffer_row, window, cx)
23309                                    });
23310                                } else {
23311                                    editor.update(cx, |editor, cx| {
23312                                        editor.unfold_at(buffer_row, window, cx)
23313                                    });
23314                                }
23315                            });
23316                        return Some((render_toggle)(
23317                            buffer_row,
23318                            folded,
23319                            toggle_callback,
23320                            window,
23321                            cx,
23322                        ));
23323                    }
23324                }
23325            }
23326        }
23327
23328        is_foldable |= self.starts_indent(buffer_row);
23329
23330        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23331            Some(
23332                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23333                    .toggle_state(folded)
23334                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23335                        if folded {
23336                            this.unfold_at(buffer_row, window, cx);
23337                        } else {
23338                            this.fold_at(buffer_row, window, cx);
23339                        }
23340                    }))
23341                    .into_any_element(),
23342            )
23343        } else {
23344            None
23345        }
23346    }
23347
23348    pub fn render_crease_trailer(
23349        &self,
23350        buffer_row: MultiBufferRow,
23351        window: &mut Window,
23352        cx: &mut App,
23353    ) -> Option<AnyElement> {
23354        let folded = self.is_line_folded(buffer_row);
23355        if let Crease::Inline { render_trailer, .. } = self
23356            .crease_snapshot
23357            .query_row(buffer_row, &self.buffer_snapshot)?
23358        {
23359            let render_trailer = render_trailer.as_ref()?;
23360            Some(render_trailer(buffer_row, folded, window, cx))
23361        } else {
23362            None
23363        }
23364    }
23365}
23366
23367impl Deref for EditorSnapshot {
23368    type Target = DisplaySnapshot;
23369
23370    fn deref(&self) -> &Self::Target {
23371        &self.display_snapshot
23372    }
23373}
23374
23375#[derive(Clone, Debug, PartialEq, Eq)]
23376pub enum EditorEvent {
23377    InputIgnored {
23378        text: Arc<str>,
23379    },
23380    InputHandled {
23381        utf16_range_to_replace: Option<Range<isize>>,
23382        text: Arc<str>,
23383    },
23384    ExcerptsAdded {
23385        buffer: Entity<Buffer>,
23386        predecessor: ExcerptId,
23387        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23388    },
23389    ExcerptsRemoved {
23390        ids: Vec<ExcerptId>,
23391        removed_buffer_ids: Vec<BufferId>,
23392    },
23393    BufferFoldToggled {
23394        ids: Vec<ExcerptId>,
23395        folded: bool,
23396    },
23397    ExcerptsEdited {
23398        ids: Vec<ExcerptId>,
23399    },
23400    ExcerptsExpanded {
23401        ids: Vec<ExcerptId>,
23402    },
23403    BufferEdited,
23404    Edited {
23405        transaction_id: clock::Lamport,
23406    },
23407    Reparsed(BufferId),
23408    Focused,
23409    FocusedIn,
23410    Blurred,
23411    DirtyChanged,
23412    Saved,
23413    TitleChanged,
23414    SelectionsChanged {
23415        local: bool,
23416    },
23417    ScrollPositionChanged {
23418        local: bool,
23419        autoscroll: bool,
23420    },
23421    TransactionUndone {
23422        transaction_id: clock::Lamport,
23423    },
23424    TransactionBegun {
23425        transaction_id: clock::Lamport,
23426    },
23427    CursorShapeChanged,
23428    BreadcrumbsChanged,
23429    PushedToNavHistory {
23430        anchor: Anchor,
23431        is_deactivate: bool,
23432    },
23433}
23434
23435impl EventEmitter<EditorEvent> for Editor {}
23436
23437impl Focusable for Editor {
23438    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23439        self.focus_handle.clone()
23440    }
23441}
23442
23443impl Render for Editor {
23444    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23445        let settings = ThemeSettings::get_global(cx);
23446
23447        let mut text_style = match self.mode {
23448            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23449                color: cx.theme().colors().editor_foreground,
23450                font_family: settings.ui_font.family.clone(),
23451                font_features: settings.ui_font.features.clone(),
23452                font_fallbacks: settings.ui_font.fallbacks.clone(),
23453                font_size: rems(0.875).into(),
23454                font_weight: settings.ui_font.weight,
23455                line_height: relative(settings.buffer_line_height.value()),
23456                ..Default::default()
23457            },
23458            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23459                color: cx.theme().colors().editor_foreground,
23460                font_family: settings.buffer_font.family.clone(),
23461                font_features: settings.buffer_font.features.clone(),
23462                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23463                font_size: settings.buffer_font_size(cx).into(),
23464                font_weight: settings.buffer_font.weight,
23465                line_height: relative(settings.buffer_line_height.value()),
23466                ..Default::default()
23467            },
23468        };
23469        if let Some(text_style_refinement) = &self.text_style_refinement {
23470            text_style.refine(text_style_refinement)
23471        }
23472
23473        let background = match self.mode {
23474            EditorMode::SingleLine => cx.theme().system().transparent,
23475            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23476            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23477            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23478        };
23479
23480        EditorElement::new(
23481            &cx.entity(),
23482            EditorStyle {
23483                background,
23484                border: cx.theme().colors().border,
23485                local_player: cx.theme().players().local(),
23486                text: text_style,
23487                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23488                syntax: cx.theme().syntax().clone(),
23489                status: cx.theme().status().clone(),
23490                inlay_hints_style: make_inlay_hints_style(cx),
23491                edit_prediction_styles: make_suggestion_styles(cx),
23492                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23493                show_underlines: self.diagnostics_enabled(),
23494            },
23495        )
23496    }
23497}
23498
23499impl EntityInputHandler for Editor {
23500    fn text_for_range(
23501        &mut self,
23502        range_utf16: Range<usize>,
23503        adjusted_range: &mut Option<Range<usize>>,
23504        _: &mut Window,
23505        cx: &mut Context<Self>,
23506    ) -> Option<String> {
23507        let snapshot = self.buffer.read(cx).read(cx);
23508        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23509        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23510        if (start.0..end.0) != range_utf16 {
23511            adjusted_range.replace(start.0..end.0);
23512        }
23513        Some(snapshot.text_for_range(start..end).collect())
23514    }
23515
23516    fn selected_text_range(
23517        &mut self,
23518        ignore_disabled_input: bool,
23519        _: &mut Window,
23520        cx: &mut Context<Self>,
23521    ) -> Option<UTF16Selection> {
23522        // Prevent the IME menu from appearing when holding down an alphabetic key
23523        // while input is disabled.
23524        if !ignore_disabled_input && !self.input_enabled {
23525            return None;
23526        }
23527
23528        let selection = self.selections.newest::<OffsetUtf16>(cx);
23529        let range = selection.range();
23530
23531        Some(UTF16Selection {
23532            range: range.start.0..range.end.0,
23533            reversed: selection.reversed,
23534        })
23535    }
23536
23537    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23538        let snapshot = self.buffer.read(cx).read(cx);
23539        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23540        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23541    }
23542
23543    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23544        self.clear_highlights::<InputComposition>(cx);
23545        self.ime_transaction.take();
23546    }
23547
23548    fn replace_text_in_range(
23549        &mut self,
23550        range_utf16: Option<Range<usize>>,
23551        text: &str,
23552        window: &mut Window,
23553        cx: &mut Context<Self>,
23554    ) {
23555        if !self.input_enabled {
23556            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23557            return;
23558        }
23559
23560        self.transact(window, cx, |this, window, cx| {
23561            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23562                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23563                Some(this.selection_replacement_ranges(range_utf16, cx))
23564            } else {
23565                this.marked_text_ranges(cx)
23566            };
23567
23568            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23569                let newest_selection_id = this.selections.newest_anchor().id;
23570                this.selections
23571                    .all::<OffsetUtf16>(cx)
23572                    .iter()
23573                    .zip(ranges_to_replace.iter())
23574                    .find_map(|(selection, range)| {
23575                        if selection.id == newest_selection_id {
23576                            Some(
23577                                (range.start.0 as isize - selection.head().0 as isize)
23578                                    ..(range.end.0 as isize - selection.head().0 as isize),
23579                            )
23580                        } else {
23581                            None
23582                        }
23583                    })
23584            });
23585
23586            cx.emit(EditorEvent::InputHandled {
23587                utf16_range_to_replace: range_to_replace,
23588                text: text.into(),
23589            });
23590
23591            if let Some(new_selected_ranges) = new_selected_ranges {
23592                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23593                    selections.select_ranges(new_selected_ranges)
23594                });
23595                this.backspace(&Default::default(), window, cx);
23596            }
23597
23598            this.handle_input(text, window, cx);
23599        });
23600
23601        if let Some(transaction) = self.ime_transaction {
23602            self.buffer.update(cx, |buffer, cx| {
23603                buffer.group_until_transaction(transaction, cx);
23604            });
23605        }
23606
23607        self.unmark_text(window, cx);
23608    }
23609
23610    fn replace_and_mark_text_in_range(
23611        &mut self,
23612        range_utf16: Option<Range<usize>>,
23613        text: &str,
23614        new_selected_range_utf16: Option<Range<usize>>,
23615        window: &mut Window,
23616        cx: &mut Context<Self>,
23617    ) {
23618        if !self.input_enabled {
23619            return;
23620        }
23621
23622        let transaction = self.transact(window, cx, |this, window, cx| {
23623            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23624                let snapshot = this.buffer.read(cx).read(cx);
23625                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23626                    for marked_range in &mut marked_ranges {
23627                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23628                        marked_range.start.0 += relative_range_utf16.start;
23629                        marked_range.start =
23630                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23631                        marked_range.end =
23632                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23633                    }
23634                }
23635                Some(marked_ranges)
23636            } else if let Some(range_utf16) = range_utf16 {
23637                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23638                Some(this.selection_replacement_ranges(range_utf16, cx))
23639            } else {
23640                None
23641            };
23642
23643            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23644                let newest_selection_id = this.selections.newest_anchor().id;
23645                this.selections
23646                    .all::<OffsetUtf16>(cx)
23647                    .iter()
23648                    .zip(ranges_to_replace.iter())
23649                    .find_map(|(selection, range)| {
23650                        if selection.id == newest_selection_id {
23651                            Some(
23652                                (range.start.0 as isize - selection.head().0 as isize)
23653                                    ..(range.end.0 as isize - selection.head().0 as isize),
23654                            )
23655                        } else {
23656                            None
23657                        }
23658                    })
23659            });
23660
23661            cx.emit(EditorEvent::InputHandled {
23662                utf16_range_to_replace: range_to_replace,
23663                text: text.into(),
23664            });
23665
23666            if let Some(ranges) = ranges_to_replace {
23667                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23668                    s.select_ranges(ranges)
23669                });
23670            }
23671
23672            let marked_ranges = {
23673                let snapshot = this.buffer.read(cx).read(cx);
23674                this.selections
23675                    .disjoint_anchors_arc()
23676                    .iter()
23677                    .map(|selection| {
23678                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23679                    })
23680                    .collect::<Vec<_>>()
23681            };
23682
23683            if text.is_empty() {
23684                this.unmark_text(window, cx);
23685            } else {
23686                this.highlight_text::<InputComposition>(
23687                    marked_ranges.clone(),
23688                    HighlightStyle {
23689                        underline: Some(UnderlineStyle {
23690                            thickness: px(1.),
23691                            color: None,
23692                            wavy: false,
23693                        }),
23694                        ..Default::default()
23695                    },
23696                    cx,
23697                );
23698            }
23699
23700            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23701            let use_autoclose = this.use_autoclose;
23702            let use_auto_surround = this.use_auto_surround;
23703            this.set_use_autoclose(false);
23704            this.set_use_auto_surround(false);
23705            this.handle_input(text, window, cx);
23706            this.set_use_autoclose(use_autoclose);
23707            this.set_use_auto_surround(use_auto_surround);
23708
23709            if let Some(new_selected_range) = new_selected_range_utf16 {
23710                let snapshot = this.buffer.read(cx).read(cx);
23711                let new_selected_ranges = marked_ranges
23712                    .into_iter()
23713                    .map(|marked_range| {
23714                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23715                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23716                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23717                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23718                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23719                    })
23720                    .collect::<Vec<_>>();
23721
23722                drop(snapshot);
23723                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23724                    selections.select_ranges(new_selected_ranges)
23725                });
23726            }
23727        });
23728
23729        self.ime_transaction = self.ime_transaction.or(transaction);
23730        if let Some(transaction) = self.ime_transaction {
23731            self.buffer.update(cx, |buffer, cx| {
23732                buffer.group_until_transaction(transaction, cx);
23733            });
23734        }
23735
23736        if self.text_highlights::<InputComposition>(cx).is_none() {
23737            self.ime_transaction.take();
23738        }
23739    }
23740
23741    fn bounds_for_range(
23742        &mut self,
23743        range_utf16: Range<usize>,
23744        element_bounds: gpui::Bounds<Pixels>,
23745        window: &mut Window,
23746        cx: &mut Context<Self>,
23747    ) -> Option<gpui::Bounds<Pixels>> {
23748        let text_layout_details = self.text_layout_details(window);
23749        let CharacterDimensions {
23750            em_width,
23751            em_advance,
23752            line_height,
23753        } = self.character_dimensions(window);
23754
23755        let snapshot = self.snapshot(window, cx);
23756        let scroll_position = snapshot.scroll_position();
23757        let scroll_left = scroll_position.x * em_advance;
23758
23759        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23760        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23761            + self.gutter_dimensions.full_width();
23762        let y = line_height * (start.row().as_f32() - scroll_position.y);
23763
23764        Some(Bounds {
23765            origin: element_bounds.origin + point(x, y),
23766            size: size(em_width, line_height),
23767        })
23768    }
23769
23770    fn character_index_for_point(
23771        &mut self,
23772        point: gpui::Point<Pixels>,
23773        _window: &mut Window,
23774        _cx: &mut Context<Self>,
23775    ) -> Option<usize> {
23776        let position_map = self.last_position_map.as_ref()?;
23777        if !position_map.text_hitbox.contains(&point) {
23778            return None;
23779        }
23780        let display_point = position_map.point_for_position(point).previous_valid;
23781        let anchor = position_map
23782            .snapshot
23783            .display_point_to_anchor(display_point, Bias::Left);
23784        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23785        Some(utf16_offset.0)
23786    }
23787}
23788
23789trait SelectionExt {
23790    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23791    fn spanned_rows(
23792        &self,
23793        include_end_if_at_line_start: bool,
23794        map: &DisplaySnapshot,
23795    ) -> Range<MultiBufferRow>;
23796}
23797
23798impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23799    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23800        let start = self
23801            .start
23802            .to_point(&map.buffer_snapshot)
23803            .to_display_point(map);
23804        let end = self
23805            .end
23806            .to_point(&map.buffer_snapshot)
23807            .to_display_point(map);
23808        if self.reversed {
23809            end..start
23810        } else {
23811            start..end
23812        }
23813    }
23814
23815    fn spanned_rows(
23816        &self,
23817        include_end_if_at_line_start: bool,
23818        map: &DisplaySnapshot,
23819    ) -> Range<MultiBufferRow> {
23820        let start = self.start.to_point(&map.buffer_snapshot);
23821        let mut end = self.end.to_point(&map.buffer_snapshot);
23822        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23823            end.row -= 1;
23824        }
23825
23826        let buffer_start = map.prev_line_boundary(start).0;
23827        let buffer_end = map.next_line_boundary(end).0;
23828        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23829    }
23830}
23831
23832impl<T: InvalidationRegion> InvalidationStack<T> {
23833    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23834    where
23835        S: Clone + ToOffset,
23836    {
23837        while let Some(region) = self.last() {
23838            let all_selections_inside_invalidation_ranges =
23839                if selections.len() == region.ranges().len() {
23840                    selections
23841                        .iter()
23842                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23843                        .all(|(selection, invalidation_range)| {
23844                            let head = selection.head().to_offset(buffer);
23845                            invalidation_range.start <= head && invalidation_range.end >= head
23846                        })
23847                } else {
23848                    false
23849                };
23850
23851            if all_selections_inside_invalidation_ranges {
23852                break;
23853            } else {
23854                self.pop();
23855            }
23856        }
23857    }
23858}
23859
23860impl<T> Default for InvalidationStack<T> {
23861    fn default() -> Self {
23862        Self(Default::default())
23863    }
23864}
23865
23866impl<T> Deref for InvalidationStack<T> {
23867    type Target = Vec<T>;
23868
23869    fn deref(&self) -> &Self::Target {
23870        &self.0
23871    }
23872}
23873
23874impl<T> DerefMut for InvalidationStack<T> {
23875    fn deref_mut(&mut self) -> &mut Self::Target {
23876        &mut self.0
23877    }
23878}
23879
23880impl InvalidationRegion for SnippetState {
23881    fn ranges(&self) -> &[Range<Anchor>] {
23882        &self.ranges[self.active_index]
23883    }
23884}
23885
23886fn edit_prediction_edit_text(
23887    current_snapshot: &BufferSnapshot,
23888    edits: &[(Range<Anchor>, String)],
23889    edit_preview: &EditPreview,
23890    include_deletions: bool,
23891    cx: &App,
23892) -> HighlightedText {
23893    let edits = edits
23894        .iter()
23895        .map(|(anchor, text)| {
23896            (
23897                anchor.start.text_anchor..anchor.end.text_anchor,
23898                text.clone(),
23899            )
23900        })
23901        .collect::<Vec<_>>();
23902
23903    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23904}
23905
23906fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23907    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23908    // Just show the raw edit text with basic styling
23909    let mut text = String::new();
23910    let mut highlights = Vec::new();
23911
23912    let insertion_highlight_style = HighlightStyle {
23913        color: Some(cx.theme().colors().text),
23914        ..Default::default()
23915    };
23916
23917    for (_, edit_text) in edits {
23918        let start_offset = text.len();
23919        text.push_str(edit_text);
23920        let end_offset = text.len();
23921
23922        if start_offset < end_offset {
23923            highlights.push((start_offset..end_offset, insertion_highlight_style));
23924        }
23925    }
23926
23927    HighlightedText {
23928        text: text.into(),
23929        highlights,
23930    }
23931}
23932
23933pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23934    match severity {
23935        lsp::DiagnosticSeverity::ERROR => colors.error,
23936        lsp::DiagnosticSeverity::WARNING => colors.warning,
23937        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23938        lsp::DiagnosticSeverity::HINT => colors.info,
23939        _ => colors.ignored,
23940    }
23941}
23942
23943pub fn styled_runs_for_code_label<'a>(
23944    label: &'a CodeLabel,
23945    syntax_theme: &'a theme::SyntaxTheme,
23946) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23947    let fade_out = HighlightStyle {
23948        fade_out: Some(0.35),
23949        ..Default::default()
23950    };
23951
23952    let mut prev_end = label.filter_range.end;
23953    label
23954        .runs
23955        .iter()
23956        .enumerate()
23957        .flat_map(move |(ix, (range, highlight_id))| {
23958            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23959                style
23960            } else {
23961                return Default::default();
23962            };
23963            let muted_style = style.highlight(fade_out);
23964
23965            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23966            if range.start >= label.filter_range.end {
23967                if range.start > prev_end {
23968                    runs.push((prev_end..range.start, fade_out));
23969                }
23970                runs.push((range.clone(), muted_style));
23971            } else if range.end <= label.filter_range.end {
23972                runs.push((range.clone(), style));
23973            } else {
23974                runs.push((range.start..label.filter_range.end, style));
23975                runs.push((label.filter_range.end..range.end, muted_style));
23976            }
23977            prev_end = cmp::max(prev_end, range.end);
23978
23979            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23980                runs.push((prev_end..label.text.len(), fade_out));
23981            }
23982
23983            runs
23984        })
23985}
23986
23987pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23988    let mut prev_index = 0;
23989    let mut prev_codepoint: Option<char> = None;
23990    text.char_indices()
23991        .chain([(text.len(), '\0')])
23992        .filter_map(move |(index, codepoint)| {
23993            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23994            let is_boundary = index == text.len()
23995                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23996                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23997            if is_boundary {
23998                let chunk = &text[prev_index..index];
23999                prev_index = index;
24000                Some(chunk)
24001            } else {
24002                None
24003            }
24004        })
24005}
24006
24007pub trait RangeToAnchorExt: Sized {
24008    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24009
24010    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24011        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
24012        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24013    }
24014}
24015
24016impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24017    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24018        let start_offset = self.start.to_offset(snapshot);
24019        let end_offset = self.end.to_offset(snapshot);
24020        if start_offset == end_offset {
24021            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24022        } else {
24023            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24024        }
24025    }
24026}
24027
24028pub trait RowExt {
24029    fn as_f32(&self) -> f32;
24030
24031    fn next_row(&self) -> Self;
24032
24033    fn previous_row(&self) -> Self;
24034
24035    fn minus(&self, other: Self) -> u32;
24036}
24037
24038impl RowExt for DisplayRow {
24039    fn as_f32(&self) -> f32 {
24040        self.0 as f32
24041    }
24042
24043    fn next_row(&self) -> Self {
24044        Self(self.0 + 1)
24045    }
24046
24047    fn previous_row(&self) -> Self {
24048        Self(self.0.saturating_sub(1))
24049    }
24050
24051    fn minus(&self, other: Self) -> u32 {
24052        self.0 - other.0
24053    }
24054}
24055
24056impl RowExt for MultiBufferRow {
24057    fn as_f32(&self) -> f32 {
24058        self.0 as f32
24059    }
24060
24061    fn next_row(&self) -> Self {
24062        Self(self.0 + 1)
24063    }
24064
24065    fn previous_row(&self) -> Self {
24066        Self(self.0.saturating_sub(1))
24067    }
24068
24069    fn minus(&self, other: Self) -> u32 {
24070        self.0 - other.0
24071    }
24072}
24073
24074trait RowRangeExt {
24075    type Row;
24076
24077    fn len(&self) -> usize;
24078
24079    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24080}
24081
24082impl RowRangeExt for Range<MultiBufferRow> {
24083    type Row = MultiBufferRow;
24084
24085    fn len(&self) -> usize {
24086        (self.end.0 - self.start.0) as usize
24087    }
24088
24089    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24090        (self.start.0..self.end.0).map(MultiBufferRow)
24091    }
24092}
24093
24094impl RowRangeExt for Range<DisplayRow> {
24095    type Row = DisplayRow;
24096
24097    fn len(&self) -> usize {
24098        (self.end.0 - self.start.0) as usize
24099    }
24100
24101    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24102        (self.start.0..self.end.0).map(DisplayRow)
24103    }
24104}
24105
24106/// If select range has more than one line, we
24107/// just point the cursor to range.start.
24108fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24109    if range.start.row == range.end.row {
24110        range
24111    } else {
24112        range.start..range.start
24113    }
24114}
24115pub struct KillRing(ClipboardItem);
24116impl Global for KillRing {}
24117
24118const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24119
24120enum BreakpointPromptEditAction {
24121    Log,
24122    Condition,
24123    HitCondition,
24124}
24125
24126struct BreakpointPromptEditor {
24127    pub(crate) prompt: Entity<Editor>,
24128    editor: WeakEntity<Editor>,
24129    breakpoint_anchor: Anchor,
24130    breakpoint: Breakpoint,
24131    edit_action: BreakpointPromptEditAction,
24132    block_ids: HashSet<CustomBlockId>,
24133    editor_margins: Arc<Mutex<EditorMargins>>,
24134    _subscriptions: Vec<Subscription>,
24135}
24136
24137impl BreakpointPromptEditor {
24138    const MAX_LINES: u8 = 4;
24139
24140    fn new(
24141        editor: WeakEntity<Editor>,
24142        breakpoint_anchor: Anchor,
24143        breakpoint: Breakpoint,
24144        edit_action: BreakpointPromptEditAction,
24145        window: &mut Window,
24146        cx: &mut Context<Self>,
24147    ) -> Self {
24148        let base_text = match edit_action {
24149            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24150            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24151            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24152        }
24153        .map(|msg| msg.to_string())
24154        .unwrap_or_default();
24155
24156        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24157        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24158
24159        let prompt = cx.new(|cx| {
24160            let mut prompt = Editor::new(
24161                EditorMode::AutoHeight {
24162                    min_lines: 1,
24163                    max_lines: Some(Self::MAX_LINES as usize),
24164                },
24165                buffer,
24166                None,
24167                window,
24168                cx,
24169            );
24170            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24171            prompt.set_show_cursor_when_unfocused(false, cx);
24172            prompt.set_placeholder_text(
24173                match edit_action {
24174                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24175                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24176                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24177                },
24178                window,
24179                cx,
24180            );
24181
24182            prompt
24183        });
24184
24185        Self {
24186            prompt,
24187            editor,
24188            breakpoint_anchor,
24189            breakpoint,
24190            edit_action,
24191            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24192            block_ids: Default::default(),
24193            _subscriptions: vec![],
24194        }
24195    }
24196
24197    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24198        self.block_ids.extend(block_ids)
24199    }
24200
24201    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24202        if let Some(editor) = self.editor.upgrade() {
24203            let message = self
24204                .prompt
24205                .read(cx)
24206                .buffer
24207                .read(cx)
24208                .as_singleton()
24209                .expect("A multi buffer in breakpoint prompt isn't possible")
24210                .read(cx)
24211                .as_rope()
24212                .to_string();
24213
24214            editor.update(cx, |editor, cx| {
24215                editor.edit_breakpoint_at_anchor(
24216                    self.breakpoint_anchor,
24217                    self.breakpoint.clone(),
24218                    match self.edit_action {
24219                        BreakpointPromptEditAction::Log => {
24220                            BreakpointEditAction::EditLogMessage(message.into())
24221                        }
24222                        BreakpointPromptEditAction::Condition => {
24223                            BreakpointEditAction::EditCondition(message.into())
24224                        }
24225                        BreakpointPromptEditAction::HitCondition => {
24226                            BreakpointEditAction::EditHitCondition(message.into())
24227                        }
24228                    },
24229                    cx,
24230                );
24231
24232                editor.remove_blocks(self.block_ids.clone(), None, cx);
24233                cx.focus_self(window);
24234            });
24235        }
24236    }
24237
24238    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24239        self.editor
24240            .update(cx, |editor, cx| {
24241                editor.remove_blocks(self.block_ids.clone(), None, cx);
24242                window.focus(&editor.focus_handle);
24243            })
24244            .log_err();
24245    }
24246
24247    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24248        let settings = ThemeSettings::get_global(cx);
24249        let text_style = TextStyle {
24250            color: if self.prompt.read(cx).read_only(cx) {
24251                cx.theme().colors().text_disabled
24252            } else {
24253                cx.theme().colors().text
24254            },
24255            font_family: settings.buffer_font.family.clone(),
24256            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24257            font_size: settings.buffer_font_size(cx).into(),
24258            font_weight: settings.buffer_font.weight,
24259            line_height: relative(settings.buffer_line_height.value()),
24260            ..Default::default()
24261        };
24262        EditorElement::new(
24263            &self.prompt,
24264            EditorStyle {
24265                background: cx.theme().colors().editor_background,
24266                local_player: cx.theme().players().local(),
24267                text: text_style,
24268                ..Default::default()
24269            },
24270        )
24271    }
24272}
24273
24274impl Render for BreakpointPromptEditor {
24275    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24276        let editor_margins = *self.editor_margins.lock();
24277        let gutter_dimensions = editor_margins.gutter;
24278        h_flex()
24279            .key_context("Editor")
24280            .bg(cx.theme().colors().editor_background)
24281            .border_y_1()
24282            .border_color(cx.theme().status().info_border)
24283            .size_full()
24284            .py(window.line_height() / 2.5)
24285            .on_action(cx.listener(Self::confirm))
24286            .on_action(cx.listener(Self::cancel))
24287            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24288            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24289    }
24290}
24291
24292impl Focusable for BreakpointPromptEditor {
24293    fn focus_handle(&self, cx: &App) -> FocusHandle {
24294        self.prompt.focus_handle(cx)
24295    }
24296}
24297
24298fn all_edits_insertions_or_deletions(
24299    edits: &Vec<(Range<Anchor>, String)>,
24300    snapshot: &MultiBufferSnapshot,
24301) -> bool {
24302    let mut all_insertions = true;
24303    let mut all_deletions = true;
24304
24305    for (range, new_text) in edits.iter() {
24306        let range_is_empty = range.to_offset(snapshot).is_empty();
24307        let text_is_empty = new_text.is_empty();
24308
24309        if range_is_empty != text_is_empty {
24310            if range_is_empty {
24311                all_deletions = false;
24312            } else {
24313                all_insertions = false;
24314            }
24315        } else {
24316            return false;
24317        }
24318
24319        if !all_insertions && !all_deletions {
24320            return false;
24321        }
24322    }
24323    all_insertions || all_deletions
24324}
24325
24326struct MissingEditPredictionKeybindingTooltip;
24327
24328impl Render for MissingEditPredictionKeybindingTooltip {
24329    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24330        ui::tooltip_container(window, cx, |container, _, cx| {
24331            container
24332                .flex_shrink_0()
24333                .max_w_80()
24334                .min_h(rems_from_px(124.))
24335                .justify_between()
24336                .child(
24337                    v_flex()
24338                        .flex_1()
24339                        .text_ui_sm(cx)
24340                        .child(Label::new("Conflict with Accept Keybinding"))
24341                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24342                )
24343                .child(
24344                    h_flex()
24345                        .pb_1()
24346                        .gap_1()
24347                        .items_end()
24348                        .w_full()
24349                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24350                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24351                        }))
24352                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24353                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24354                        })),
24355                )
24356        })
24357    }
24358}
24359
24360#[derive(Debug, Clone, Copy, PartialEq)]
24361pub struct LineHighlight {
24362    pub background: Background,
24363    pub border: Option<gpui::Hsla>,
24364    pub include_gutter: bool,
24365    pub type_id: Option<TypeId>,
24366}
24367
24368struct LineManipulationResult {
24369    pub new_text: String,
24370    pub line_count_before: usize,
24371    pub line_count_after: usize,
24372}
24373
24374fn render_diff_hunk_controls(
24375    row: u32,
24376    status: &DiffHunkStatus,
24377    hunk_range: Range<Anchor>,
24378    is_created_file: bool,
24379    line_height: Pixels,
24380    editor: &Entity<Editor>,
24381    _window: &mut Window,
24382    cx: &mut App,
24383) -> AnyElement {
24384    h_flex()
24385        .h(line_height)
24386        .mr_1()
24387        .gap_1()
24388        .px_0p5()
24389        .pb_1()
24390        .border_x_1()
24391        .border_b_1()
24392        .border_color(cx.theme().colors().border_variant)
24393        .rounded_b_lg()
24394        .bg(cx.theme().colors().editor_background)
24395        .gap_1()
24396        .block_mouse_except_scroll()
24397        .shadow_md()
24398        .child(if status.has_secondary_hunk() {
24399            Button::new(("stage", row as u64), "Stage")
24400                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24401                .tooltip({
24402                    let focus_handle = editor.focus_handle(cx);
24403                    move |window, cx| {
24404                        Tooltip::for_action_in(
24405                            "Stage Hunk",
24406                            &::git::ToggleStaged,
24407                            &focus_handle,
24408                            window,
24409                            cx,
24410                        )
24411                    }
24412                })
24413                .on_click({
24414                    let editor = editor.clone();
24415                    move |_event, _window, cx| {
24416                        editor.update(cx, |editor, cx| {
24417                            editor.stage_or_unstage_diff_hunks(
24418                                true,
24419                                vec![hunk_range.start..hunk_range.start],
24420                                cx,
24421                            );
24422                        });
24423                    }
24424                })
24425        } else {
24426            Button::new(("unstage", row as u64), "Unstage")
24427                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24428                .tooltip({
24429                    let focus_handle = editor.focus_handle(cx);
24430                    move |window, cx| {
24431                        Tooltip::for_action_in(
24432                            "Unstage Hunk",
24433                            &::git::ToggleStaged,
24434                            &focus_handle,
24435                            window,
24436                            cx,
24437                        )
24438                    }
24439                })
24440                .on_click({
24441                    let editor = editor.clone();
24442                    move |_event, _window, cx| {
24443                        editor.update(cx, |editor, cx| {
24444                            editor.stage_or_unstage_diff_hunks(
24445                                false,
24446                                vec![hunk_range.start..hunk_range.start],
24447                                cx,
24448                            );
24449                        });
24450                    }
24451                })
24452        })
24453        .child(
24454            Button::new(("restore", row as u64), "Restore")
24455                .tooltip({
24456                    let focus_handle = editor.focus_handle(cx);
24457                    move |window, cx| {
24458                        Tooltip::for_action_in(
24459                            "Restore Hunk",
24460                            &::git::Restore,
24461                            &focus_handle,
24462                            window,
24463                            cx,
24464                        )
24465                    }
24466                })
24467                .on_click({
24468                    let editor = editor.clone();
24469                    move |_event, window, cx| {
24470                        editor.update(cx, |editor, cx| {
24471                            let snapshot = editor.snapshot(window, cx);
24472                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24473                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24474                        });
24475                    }
24476                })
24477                .disabled(is_created_file),
24478        )
24479        .when(
24480            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24481            |el| {
24482                el.child(
24483                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24484                        .shape(IconButtonShape::Square)
24485                        .icon_size(IconSize::Small)
24486                        // .disabled(!has_multiple_hunks)
24487                        .tooltip({
24488                            let focus_handle = editor.focus_handle(cx);
24489                            move |window, cx| {
24490                                Tooltip::for_action_in(
24491                                    "Next Hunk",
24492                                    &GoToHunk,
24493                                    &focus_handle,
24494                                    window,
24495                                    cx,
24496                                )
24497                            }
24498                        })
24499                        .on_click({
24500                            let editor = editor.clone();
24501                            move |_event, window, cx| {
24502                                editor.update(cx, |editor, cx| {
24503                                    let snapshot = editor.snapshot(window, cx);
24504                                    let position =
24505                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24506                                    editor.go_to_hunk_before_or_after_position(
24507                                        &snapshot,
24508                                        position,
24509                                        Direction::Next,
24510                                        window,
24511                                        cx,
24512                                    );
24513                                    editor.expand_selected_diff_hunks(cx);
24514                                });
24515                            }
24516                        }),
24517                )
24518                .child(
24519                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24520                        .shape(IconButtonShape::Square)
24521                        .icon_size(IconSize::Small)
24522                        // .disabled(!has_multiple_hunks)
24523                        .tooltip({
24524                            let focus_handle = editor.focus_handle(cx);
24525                            move |window, cx| {
24526                                Tooltip::for_action_in(
24527                                    "Previous Hunk",
24528                                    &GoToPreviousHunk,
24529                                    &focus_handle,
24530                                    window,
24531                                    cx,
24532                                )
24533                            }
24534                        })
24535                        .on_click({
24536                            let editor = editor.clone();
24537                            move |_event, window, cx| {
24538                                editor.update(cx, |editor, cx| {
24539                                    let snapshot = editor.snapshot(window, cx);
24540                                    let point =
24541                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24542                                    editor.go_to_hunk_before_or_after_position(
24543                                        &snapshot,
24544                                        point,
24545                                        Direction::Prev,
24546                                        window,
24547                                        cx,
24548                                    );
24549                                    editor.expand_selected_diff_hunks(cx);
24550                                });
24551                            }
24552                        }),
24553                )
24554            },
24555        )
24556        .into_any_element()
24557}
24558
24559pub fn multibuffer_context_lines(cx: &App) -> u32 {
24560    EditorSettings::try_get(cx)
24561        .map(|settings| settings.excerpt_context_lines)
24562        .unwrap_or(2)
24563        .min(32)
24564}