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, ShowScrollbar,
   59};
   60pub use editor_settings_controls::*;
   61pub use element::{
   62    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, ParticipantIndex};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CodeLabel, CursorShape, DiagnosticEntry,
  125    DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize,
  126    Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject,
  127    TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  152    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  153    ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{
  164        DiagnosticSeverity, GitGutterSetting, GoToDiagnosticSeverityFilter, ProjectSettings,
  165    },
  166};
  167use rand::seq::SliceRandom;
  168use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  169use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  170use selections_collection::{
  171    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  172};
  173use serde::{Deserialize, Serialize};
  174use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  175use smallvec::{SmallVec, smallvec};
  176use snippet::Snippet;
  177use std::{
  178    any::TypeId,
  179    borrow::Cow,
  180    cell::OnceCell,
  181    cell::RefCell,
  182    cmp::{self, Ordering, Reverse},
  183    iter::Peekable,
  184    mem,
  185    num::NonZeroU32,
  186    ops::Not,
  187    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  188    path::{Path, PathBuf},
  189    rc::Rc,
  190    sync::Arc,
  191    time::{Duration, Instant},
  192};
  193use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  194use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  195use theme::{
  196    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  197    observe_buffer_font_size_adjustment,
  198};
  199use ui::{
  200    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  201    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  202};
  203use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  204use workspace::{
  205    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  206    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  207    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  208    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  209    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  210    searchable::SearchEvent,
  211};
  212
  213use crate::{
  214    code_context_menus::CompletionsMenuSource,
  215    editor_settings::MultiCursorModifier,
  216    hover_links::{find_url, find_url_from_range},
  217    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  218};
  219
  220pub const FILE_HEADER_HEIGHT: u32 = 2;
  221pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  222const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  223const MAX_LINE_LEN: usize = 1024;
  224const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  225const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  226pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  227#[doc(hidden)]
  228pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  229pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  230
  231pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  234
  235pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  236pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  237pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  238
  239pub type RenderDiffHunkControlsFn = Arc<
  240    dyn Fn(
  241        u32,
  242        &DiffHunkStatus,
  243        Range<Anchor>,
  244        bool,
  245        Pixels,
  246        &Entity<Editor>,
  247        &mut Window,
  248        &mut App,
  249    ) -> AnyElement,
  250>;
  251
  252enum ReportEditorEvent {
  253    Saved { auto_saved: bool },
  254    EditorOpened,
  255    Closed,
  256}
  257
  258impl ReportEditorEvent {
  259    pub fn event_type(&self) -> &'static str {
  260        match self {
  261            Self::Saved { .. } => "Editor Saved",
  262            Self::EditorOpened => "Editor Opened",
  263            Self::Closed => "Editor Closed",
  264        }
  265    }
  266}
  267
  268struct InlineValueCache {
  269    enabled: bool,
  270    inlays: Vec<InlayId>,
  271    refresh_task: Task<Option<()>>,
  272}
  273
  274impl InlineValueCache {
  275    fn new(enabled: bool) -> Self {
  276        Self {
  277            enabled,
  278            inlays: Vec::new(),
  279            refresh_task: Task::ready(None),
  280        }
  281    }
  282}
  283
  284#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  285pub enum InlayId {
  286    EditPrediction(usize),
  287    DebuggerValue(usize),
  288    // LSP
  289    Hint(usize),
  290    Color(usize),
  291}
  292
  293impl InlayId {
  294    fn id(&self) -> usize {
  295        match self {
  296            Self::EditPrediction(id) => *id,
  297            Self::DebuggerValue(id) => *id,
  298            Self::Hint(id) => *id,
  299            Self::Color(id) => *id,
  300        }
  301    }
  302}
  303
  304pub enum ActiveDebugLine {}
  305pub enum DebugStackFrameLine {}
  306enum DocumentHighlightRead {}
  307enum DocumentHighlightWrite {}
  308enum InputComposition {}
  309pub enum PendingInput {}
  310enum SelectedTextHighlight {}
  311
  312pub enum ConflictsOuter {}
  313pub enum ConflictsOurs {}
  314pub enum ConflictsTheirs {}
  315pub enum ConflictsOursMarker {}
  316pub enum ConflictsTheirsMarker {}
  317
  318#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  319pub enum Navigated {
  320    Yes,
  321    No,
  322}
  323
  324impl Navigated {
  325    pub fn from_bool(yes: bool) -> Navigated {
  326        if yes { Navigated::Yes } else { Navigated::No }
  327    }
  328}
  329
  330#[derive(Debug, Clone, PartialEq, Eq)]
  331enum DisplayDiffHunk {
  332    Folded {
  333        display_row: DisplayRow,
  334    },
  335    Unfolded {
  336        is_created_file: bool,
  337        diff_base_byte_range: Range<usize>,
  338        display_row_range: Range<DisplayRow>,
  339        multi_buffer_range: Range<Anchor>,
  340        status: DiffHunkStatus,
  341    },
  342}
  343
  344pub enum HideMouseCursorOrigin {
  345    TypingAction,
  346    MovementAction,
  347}
  348
  349pub fn init_settings(cx: &mut App) {
  350    EditorSettings::register(cx);
  351}
  352
  353pub fn init(cx: &mut App) {
  354    init_settings(cx);
  355
  356    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  357
  358    workspace::register_project_item::<Editor>(cx);
  359    workspace::FollowableViewRegistry::register::<Editor>(cx);
  360    workspace::register_serializable_item::<Editor>(cx);
  361
  362    cx.observe_new(
  363        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  364            workspace.register_action(Editor::new_file);
  365            workspace.register_action(Editor::new_file_vertical);
  366            workspace.register_action(Editor::new_file_horizontal);
  367            workspace.register_action(Editor::cancel_language_server_work);
  368            workspace.register_action(Editor::toggle_focus);
  369        },
  370    )
  371    .detach();
  372
  373    cx.on_action(move |_: &workspace::NewFile, cx| {
  374        let app_state = workspace::AppState::global(cx);
  375        if let Some(app_state) = app_state.upgrade() {
  376            workspace::open_new(
  377                Default::default(),
  378                app_state,
  379                cx,
  380                |workspace, window, cx| {
  381                    Editor::new_file(workspace, &Default::default(), window, cx)
  382                },
  383            )
  384            .detach();
  385        }
  386    });
  387    cx.on_action(move |_: &workspace::NewWindow, cx| {
  388        let app_state = workspace::AppState::global(cx);
  389        if let Some(app_state) = app_state.upgrade() {
  390            workspace::open_new(
  391                Default::default(),
  392                app_state,
  393                cx,
  394                |workspace, window, cx| {
  395                    cx.activate(true);
  396                    Editor::new_file(workspace, &Default::default(), window, cx)
  397                },
  398            )
  399            .detach();
  400        }
  401    });
  402}
  403
  404pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  405    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  406}
  407
  408pub trait DiagnosticRenderer {
  409    fn render_group(
  410        &self,
  411        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  412        buffer_id: BufferId,
  413        snapshot: EditorSnapshot,
  414        editor: WeakEntity<Editor>,
  415        cx: &mut App,
  416    ) -> Vec<BlockProperties<Anchor>>;
  417
  418    fn render_hover(
  419        &self,
  420        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  421        range: Range<Point>,
  422        buffer_id: BufferId,
  423        cx: &mut App,
  424    ) -> Option<Entity<markdown::Markdown>>;
  425
  426    fn open_link(
  427        &self,
  428        editor: &mut Editor,
  429        link: SharedString,
  430        window: &mut Window,
  431        cx: &mut Context<Editor>,
  432    );
  433}
  434
  435pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  436
  437impl GlobalDiagnosticRenderer {
  438    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  439        cx.try_global::<Self>().map(|g| g.0.clone())
  440    }
  441}
  442
  443impl gpui::Global for GlobalDiagnosticRenderer {}
  444pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  445    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  446}
  447
  448pub struct SearchWithinRange;
  449
  450trait InvalidationRegion {
  451    fn ranges(&self) -> &[Range<Anchor>];
  452}
  453
  454#[derive(Clone, Debug, PartialEq)]
  455pub enum SelectPhase {
  456    Begin {
  457        position: DisplayPoint,
  458        add: bool,
  459        click_count: usize,
  460    },
  461    BeginColumnar {
  462        position: DisplayPoint,
  463        reset: bool,
  464        mode: ColumnarMode,
  465        goal_column: u32,
  466    },
  467    Extend {
  468        position: DisplayPoint,
  469        click_count: usize,
  470    },
  471    Update {
  472        position: DisplayPoint,
  473        goal_column: u32,
  474        scroll_delta: gpui::Point<f32>,
  475    },
  476    End,
  477}
  478
  479#[derive(Clone, Debug, PartialEq)]
  480pub enum ColumnarMode {
  481    FromMouse,
  482    FromSelection,
  483}
  484
  485#[derive(Clone, Debug)]
  486pub enum SelectMode {
  487    Character,
  488    Word(Range<Anchor>),
  489    Line(Range<Anchor>),
  490    All,
  491}
  492
  493#[derive(Clone, PartialEq, Eq, Debug)]
  494pub enum EditorMode {
  495    SingleLine,
  496    AutoHeight {
  497        min_lines: usize,
  498        max_lines: Option<usize>,
  499    },
  500    Full {
  501        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  502        scale_ui_elements_with_buffer_font_size: bool,
  503        /// When set to `true`, the editor will render a background for the active line.
  504        show_active_line_background: bool,
  505        /// When set to `true`, the editor's height will be determined by its content.
  506        sized_by_content: bool,
  507    },
  508    Minimap {
  509        parent: WeakEntity<Editor>,
  510    },
  511}
  512
  513impl EditorMode {
  514    pub fn full() -> Self {
  515        Self::Full {
  516            scale_ui_elements_with_buffer_font_size: true,
  517            show_active_line_background: true,
  518            sized_by_content: false,
  519        }
  520    }
  521
  522    #[inline]
  523    pub fn is_full(&self) -> bool {
  524        matches!(self, Self::Full { .. })
  525    }
  526
  527    #[inline]
  528    pub fn is_single_line(&self) -> bool {
  529        matches!(self, Self::SingleLine { .. })
  530    }
  531
  532    #[inline]
  533    fn is_minimap(&self) -> bool {
  534        matches!(self, Self::Minimap { .. })
  535    }
  536}
  537
  538#[derive(Copy, Clone, Debug)]
  539pub enum SoftWrap {
  540    /// Prefer not to wrap at all.
  541    ///
  542    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  543    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  544    GitDiff,
  545    /// Prefer a single line generally, unless an overly long line is encountered.
  546    None,
  547    /// Soft wrap lines that exceed the editor width.
  548    EditorWidth,
  549    /// Soft wrap lines at the preferred line length.
  550    Column(u32),
  551    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  552    Bounded(u32),
  553}
  554
  555#[derive(Clone)]
  556pub struct EditorStyle {
  557    pub background: Hsla,
  558    pub border: Hsla,
  559    pub local_player: PlayerColor,
  560    pub text: TextStyle,
  561    pub scrollbar_width: Pixels,
  562    pub syntax: Arc<SyntaxTheme>,
  563    pub status: StatusColors,
  564    pub inlay_hints_style: HighlightStyle,
  565    pub edit_prediction_styles: EditPredictionStyles,
  566    pub unnecessary_code_fade: f32,
  567    pub show_underlines: bool,
  568}
  569
  570impl Default for EditorStyle {
  571    fn default() -> Self {
  572        Self {
  573            background: Hsla::default(),
  574            border: Hsla::default(),
  575            local_player: PlayerColor::default(),
  576            text: TextStyle::default(),
  577            scrollbar_width: Pixels::default(),
  578            syntax: Default::default(),
  579            // HACK: Status colors don't have a real default.
  580            // We should look into removing the status colors from the editor
  581            // style and retrieve them directly from the theme.
  582            status: StatusColors::dark(),
  583            inlay_hints_style: HighlightStyle::default(),
  584            edit_prediction_styles: EditPredictionStyles {
  585                insertion: HighlightStyle::default(),
  586                whitespace: HighlightStyle::default(),
  587            },
  588            unnecessary_code_fade: Default::default(),
  589            show_underlines: true,
  590        }
  591    }
  592}
  593
  594pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  595    let show_background = language_settings::language_settings(None, None, cx)
  596        .inlay_hints
  597        .show_background;
  598
  599    HighlightStyle {
  600        color: Some(cx.theme().status().hint),
  601        background_color: show_background.then(|| cx.theme().status().hint_background),
  602        ..HighlightStyle::default()
  603    }
  604}
  605
  606pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  607    EditPredictionStyles {
  608        insertion: HighlightStyle {
  609            color: Some(cx.theme().status().predictive),
  610            ..HighlightStyle::default()
  611        },
  612        whitespace: HighlightStyle {
  613            background_color: Some(cx.theme().status().created_background),
  614            ..HighlightStyle::default()
  615        },
  616    }
  617}
  618
  619type CompletionId = usize;
  620
  621pub(crate) enum EditDisplayMode {
  622    TabAccept,
  623    DiffPopover,
  624    Inline,
  625}
  626
  627enum EditPrediction {
  628    Edit {
  629        edits: Vec<(Range<Anchor>, String)>,
  630        edit_preview: Option<EditPreview>,
  631        display_mode: EditDisplayMode,
  632        snapshot: BufferSnapshot,
  633    },
  634    Move {
  635        target: Anchor,
  636        snapshot: BufferSnapshot,
  637    },
  638}
  639
  640struct EditPredictionState {
  641    inlay_ids: Vec<InlayId>,
  642    completion: EditPrediction,
  643    completion_id: Option<SharedString>,
  644    invalidation_range: Range<Anchor>,
  645}
  646
  647enum EditPredictionSettings {
  648    Disabled,
  649    Enabled {
  650        show_in_menu: bool,
  651        preview_requires_modifier: bool,
  652    },
  653}
  654
  655enum EditPredictionHighlight {}
  656
  657#[derive(Debug, Clone)]
  658struct InlineDiagnostic {
  659    message: SharedString,
  660    group_id: usize,
  661    is_primary: bool,
  662    start: Point,
  663    severity: lsp::DiagnosticSeverity,
  664}
  665
  666pub enum MenuEditPredictionsPolicy {
  667    Never,
  668    ByProvider,
  669}
  670
  671pub enum EditPredictionPreview {
  672    /// Modifier is not pressed
  673    Inactive { released_too_fast: bool },
  674    /// Modifier pressed
  675    Active {
  676        since: Instant,
  677        previous_scroll_position: Option<ScrollAnchor>,
  678    },
  679}
  680
  681impl EditPredictionPreview {
  682    pub fn released_too_fast(&self) -> bool {
  683        match self {
  684            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  685            EditPredictionPreview::Active { .. } => false,
  686        }
  687    }
  688
  689    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  690        if let EditPredictionPreview::Active {
  691            previous_scroll_position,
  692            ..
  693        } = self
  694        {
  695            *previous_scroll_position = scroll_position;
  696        }
  697    }
  698}
  699
  700pub struct ContextMenuOptions {
  701    pub min_entries_visible: usize,
  702    pub max_entries_visible: usize,
  703    pub placement: Option<ContextMenuPlacement>,
  704}
  705
  706#[derive(Debug, Clone, PartialEq, Eq)]
  707pub enum ContextMenuPlacement {
  708    Above,
  709    Below,
  710}
  711
  712#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  713struct EditorActionId(usize);
  714
  715impl EditorActionId {
  716    pub fn post_inc(&mut self) -> Self {
  717        let answer = self.0;
  718
  719        *self = Self(answer + 1);
  720
  721        Self(answer)
  722    }
  723}
  724
  725// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  726// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  727
  728type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  729type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  730
  731#[derive(Default)]
  732struct ScrollbarMarkerState {
  733    scrollbar_size: Size<Pixels>,
  734    dirty: bool,
  735    markers: Arc<[PaintQuad]>,
  736    pending_refresh: Option<Task<Result<()>>>,
  737}
  738
  739impl ScrollbarMarkerState {
  740    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  741        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  742    }
  743}
  744
  745#[derive(Clone, Copy, PartialEq, Eq)]
  746pub enum MinimapVisibility {
  747    Disabled,
  748    Enabled {
  749        /// The configuration currently present in the users settings.
  750        setting_configuration: bool,
  751        /// Whether to override the currently set visibility from the users setting.
  752        toggle_override: bool,
  753    },
  754}
  755
  756impl MinimapVisibility {
  757    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  758        if mode.is_full() {
  759            Self::Enabled {
  760                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  761                toggle_override: false,
  762            }
  763        } else {
  764            Self::Disabled
  765        }
  766    }
  767
  768    fn hidden(&self) -> Self {
  769        match *self {
  770            Self::Enabled {
  771                setting_configuration,
  772                ..
  773            } => Self::Enabled {
  774                setting_configuration,
  775                toggle_override: setting_configuration,
  776            },
  777            Self::Disabled => Self::Disabled,
  778        }
  779    }
  780
  781    fn disabled(&self) -> bool {
  782        matches!(*self, Self::Disabled)
  783    }
  784
  785    fn settings_visibility(&self) -> bool {
  786        match *self {
  787            Self::Enabled {
  788                setting_configuration,
  789                ..
  790            } => setting_configuration,
  791            _ => false,
  792        }
  793    }
  794
  795    fn visible(&self) -> bool {
  796        match *self {
  797            Self::Enabled {
  798                setting_configuration,
  799                toggle_override,
  800            } => setting_configuration ^ toggle_override,
  801            _ => false,
  802        }
  803    }
  804
  805    fn toggle_visibility(&self) -> Self {
  806        match *self {
  807            Self::Enabled {
  808                toggle_override,
  809                setting_configuration,
  810            } => Self::Enabled {
  811                setting_configuration,
  812                toggle_override: !toggle_override,
  813            },
  814            Self::Disabled => Self::Disabled,
  815        }
  816    }
  817}
  818
  819#[derive(Clone, Debug)]
  820struct RunnableTasks {
  821    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  822    offset: multi_buffer::Anchor,
  823    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  824    column: u32,
  825    // Values of all named captures, including those starting with '_'
  826    extra_variables: HashMap<String, String>,
  827    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  828    context_range: Range<BufferOffset>,
  829}
  830
  831impl RunnableTasks {
  832    fn resolve<'a>(
  833        &'a self,
  834        cx: &'a task::TaskContext,
  835    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  836        self.templates.iter().filter_map(|(kind, template)| {
  837            template
  838                .resolve_task(&kind.to_id_base(), cx)
  839                .map(|task| (kind.clone(), task))
  840        })
  841    }
  842}
  843
  844#[derive(Clone)]
  845pub struct ResolvedTasks {
  846    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  847    position: Anchor,
  848}
  849
  850#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  851struct BufferOffset(usize);
  852
  853// Addons allow storing per-editor state in other crates (e.g. Vim)
  854pub trait Addon: 'static {
  855    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  856
  857    fn render_buffer_header_controls(
  858        &self,
  859        _: &ExcerptInfo,
  860        _: &Window,
  861        _: &App,
  862    ) -> Option<AnyElement> {
  863        None
  864    }
  865
  866    fn to_any(&self) -> &dyn std::any::Any;
  867
  868    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  869        None
  870    }
  871}
  872
  873struct ChangeLocation {
  874    current: Option<Vec<Anchor>>,
  875    original: Vec<Anchor>,
  876}
  877impl ChangeLocation {
  878    fn locations(&self) -> &[Anchor] {
  879        self.current.as_ref().unwrap_or(&self.original)
  880    }
  881}
  882
  883/// A set of caret positions, registered when the editor was edited.
  884pub struct ChangeList {
  885    changes: Vec<ChangeLocation>,
  886    /// Currently "selected" change.
  887    position: Option<usize>,
  888}
  889
  890impl ChangeList {
  891    pub fn new() -> Self {
  892        Self {
  893            changes: Vec::new(),
  894            position: None,
  895        }
  896    }
  897
  898    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  899    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  900    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  901        if self.changes.is_empty() {
  902            return None;
  903        }
  904
  905        let prev = self.position.unwrap_or(self.changes.len());
  906        let next = if direction == Direction::Prev {
  907            prev.saturating_sub(count)
  908        } else {
  909            (prev + count).min(self.changes.len() - 1)
  910        };
  911        self.position = Some(next);
  912        self.changes.get(next).map(|change| change.locations())
  913    }
  914
  915    /// Adds a new change to the list, resetting the change list position.
  916    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  917        self.position.take();
  918        if let Some(last) = self.changes.last_mut()
  919            && group
  920        {
  921            last.current = Some(new_positions)
  922        } else {
  923            self.changes.push(ChangeLocation {
  924                original: new_positions,
  925                current: None,
  926            });
  927        }
  928    }
  929
  930    pub fn last(&self) -> Option<&[Anchor]> {
  931        self.changes.last().map(|change| change.locations())
  932    }
  933
  934    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  935        self.changes.last().map(|change| change.original.as_slice())
  936    }
  937
  938    pub fn invert_last_group(&mut self) {
  939        if let Some(last) = self.changes.last_mut()
  940            && let Some(current) = last.current.as_mut()
  941        {
  942            mem::swap(&mut last.original, current);
  943        }
  944    }
  945}
  946
  947#[derive(Clone)]
  948struct InlineBlamePopoverState {
  949    scroll_handle: ScrollHandle,
  950    commit_message: Option<ParsedCommitMessage>,
  951    markdown: Entity<Markdown>,
  952}
  953
  954struct InlineBlamePopover {
  955    position: gpui::Point<Pixels>,
  956    hide_task: Option<Task<()>>,
  957    popover_bounds: Option<Bounds<Pixels>>,
  958    popover_state: InlineBlamePopoverState,
  959    keyboard_grace: bool,
  960}
  961
  962enum SelectionDragState {
  963    /// State when no drag related activity is detected.
  964    None,
  965    /// State when the mouse is down on a selection that is about to be dragged.
  966    ReadyToDrag {
  967        selection: Selection<Anchor>,
  968        click_position: gpui::Point<Pixels>,
  969        mouse_down_time: Instant,
  970    },
  971    /// State when the mouse is dragging the selection in the editor.
  972    Dragging {
  973        selection: Selection<Anchor>,
  974        drop_cursor: Selection<Anchor>,
  975        hide_drop_cursor: bool,
  976    },
  977}
  978
  979enum ColumnarSelectionState {
  980    FromMouse {
  981        selection_tail: Anchor,
  982        display_point: Option<DisplayPoint>,
  983    },
  984    FromSelection {
  985        selection_tail: Anchor,
  986    },
  987}
  988
  989/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  990/// a breakpoint on them.
  991#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  992struct PhantomBreakpointIndicator {
  993    display_row: DisplayRow,
  994    /// There's a small debounce between hovering over the line and showing the indicator.
  995    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  996    is_active: bool,
  997    collides_with_existing_breakpoint: bool,
  998}
  999
 1000/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1001///
 1002/// See the [module level documentation](self) for more information.
 1003pub struct Editor {
 1004    focus_handle: FocusHandle,
 1005    last_focused_descendant: Option<WeakFocusHandle>,
 1006    /// The text buffer being edited
 1007    buffer: Entity<MultiBuffer>,
 1008    /// Map of how text in the buffer should be displayed.
 1009    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1010    pub display_map: Entity<DisplayMap>,
 1011    pub selections: SelectionsCollection,
 1012    pub scroll_manager: ScrollManager,
 1013    /// When inline assist editors are linked, they all render cursors because
 1014    /// typing enters text into each of them, even the ones that aren't focused.
 1015    pub(crate) show_cursor_when_unfocused: bool,
 1016    columnar_selection_state: Option<ColumnarSelectionState>,
 1017    add_selections_state: Option<AddSelectionsState>,
 1018    select_next_state: Option<SelectNextState>,
 1019    select_prev_state: Option<SelectNextState>,
 1020    selection_history: SelectionHistory,
 1021    defer_selection_effects: bool,
 1022    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1023    autoclose_regions: Vec<AutocloseRegion>,
 1024    snippet_stack: InvalidationStack<SnippetState>,
 1025    select_syntax_node_history: SelectSyntaxNodeHistory,
 1026    ime_transaction: Option<TransactionId>,
 1027    pub diagnostics_max_severity: DiagnosticSeverity,
 1028    active_diagnostics: ActiveDiagnostic,
 1029    show_inline_diagnostics: bool,
 1030    inline_diagnostics_update: Task<()>,
 1031    inline_diagnostics_enabled: bool,
 1032    diagnostics_enabled: bool,
 1033    word_completions_enabled: bool,
 1034    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1035    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1036    hard_wrap: Option<usize>,
 1037    project: Option<Entity<Project>>,
 1038    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1039    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1040    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1041    blink_manager: Entity<BlinkManager>,
 1042    show_cursor_names: bool,
 1043    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1044    pub show_local_selections: bool,
 1045    mode: EditorMode,
 1046    show_breadcrumbs: bool,
 1047    show_gutter: bool,
 1048    show_scrollbars: ScrollbarAxes,
 1049    minimap_visibility: MinimapVisibility,
 1050    offset_content: bool,
 1051    disable_expand_excerpt_buttons: bool,
 1052    show_line_numbers: Option<bool>,
 1053    use_relative_line_numbers: Option<bool>,
 1054    show_git_diff_gutter: Option<bool>,
 1055    show_code_actions: Option<bool>,
 1056    show_runnables: Option<bool>,
 1057    show_breakpoints: Option<bool>,
 1058    show_wrap_guides: Option<bool>,
 1059    show_indent_guides: Option<bool>,
 1060    placeholder_text: Option<Arc<str>>,
 1061    highlight_order: usize,
 1062    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1063    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1064    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1065    scrollbar_marker_state: ScrollbarMarkerState,
 1066    active_indent_guides_state: ActiveIndentGuidesState,
 1067    nav_history: Option<ItemNavHistory>,
 1068    context_menu: RefCell<Option<CodeContextMenu>>,
 1069    context_menu_options: Option<ContextMenuOptions>,
 1070    mouse_context_menu: Option<MouseContextMenu>,
 1071    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1072    inline_blame_popover: Option<InlineBlamePopover>,
 1073    inline_blame_popover_show_task: Option<Task<()>>,
 1074    signature_help_state: SignatureHelpState,
 1075    auto_signature_help: Option<bool>,
 1076    find_all_references_task_sources: Vec<Anchor>,
 1077    next_completion_id: CompletionId,
 1078    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1079    code_actions_task: Option<Task<Result<()>>>,
 1080    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1081    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1082    document_highlights_task: Option<Task<()>>,
 1083    linked_editing_range_task: Option<Task<Option<()>>>,
 1084    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1085    pending_rename: Option<RenameState>,
 1086    searchable: bool,
 1087    cursor_shape: CursorShape,
 1088    current_line_highlight: Option<CurrentLineHighlight>,
 1089    collapse_matches: bool,
 1090    autoindent_mode: Option<AutoindentMode>,
 1091    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1092    input_enabled: bool,
 1093    use_modal_editing: bool,
 1094    read_only: bool,
 1095    leader_id: Option<CollaboratorId>,
 1096    remote_id: Option<ViewId>,
 1097    pub hover_state: HoverState,
 1098    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1099    gutter_hovered: bool,
 1100    hovered_link_state: Option<HoveredLinkState>,
 1101    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1102    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1103    active_edit_prediction: Option<EditPredictionState>,
 1104    /// Used to prevent flickering as the user types while the menu is open
 1105    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1106    edit_prediction_settings: EditPredictionSettings,
 1107    edit_predictions_hidden_for_vim_mode: bool,
 1108    show_edit_predictions_override: Option<bool>,
 1109    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1110    edit_prediction_preview: EditPredictionPreview,
 1111    edit_prediction_indent_conflict: bool,
 1112    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1113    inlay_hint_cache: InlayHintCache,
 1114    next_inlay_id: usize,
 1115    _subscriptions: Vec<Subscription>,
 1116    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1117    gutter_dimensions: GutterDimensions,
 1118    style: Option<EditorStyle>,
 1119    text_style_refinement: Option<TextStyleRefinement>,
 1120    next_editor_action_id: EditorActionId,
 1121    editor_actions: Rc<
 1122        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1123    >,
 1124    use_autoclose: bool,
 1125    use_auto_surround: bool,
 1126    auto_replace_emoji_shortcode: bool,
 1127    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1128    show_git_blame_gutter: bool,
 1129    show_git_blame_inline: bool,
 1130    show_git_blame_inline_delay_task: Option<Task<()>>,
 1131    git_blame_inline_enabled: bool,
 1132    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1133    serialize_dirty_buffers: bool,
 1134    show_selection_menu: Option<bool>,
 1135    blame: Option<Entity<GitBlame>>,
 1136    blame_subscription: Option<Subscription>,
 1137    custom_context_menu: Option<
 1138        Box<
 1139            dyn 'static
 1140                + Fn(
 1141                    &mut Self,
 1142                    DisplayPoint,
 1143                    &mut Window,
 1144                    &mut Context<Self>,
 1145                ) -> Option<Entity<ui::ContextMenu>>,
 1146        >,
 1147    >,
 1148    last_bounds: Option<Bounds<Pixels>>,
 1149    last_position_map: Option<Rc<PositionMap>>,
 1150    expect_bounds_change: Option<Bounds<Pixels>>,
 1151    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1152    tasks_update_task: Option<Task<()>>,
 1153    breakpoint_store: Option<Entity<BreakpointStore>>,
 1154    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1155    hovered_diff_hunk_row: Option<DisplayRow>,
 1156    pull_diagnostics_task: Task<()>,
 1157    in_project_search: bool,
 1158    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1159    breadcrumb_header: Option<String>,
 1160    focused_block: Option<FocusedBlock>,
 1161    next_scroll_position: NextScrollCursorCenterTopBottom,
 1162    addons: HashMap<TypeId, Box<dyn Addon>>,
 1163    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1164    load_diff_task: Option<Shared<Task<()>>>,
 1165    /// Whether we are temporarily displaying a diff other than git's
 1166    temporary_diff_override: bool,
 1167    selection_mark_mode: bool,
 1168    toggle_fold_multiple_buffers: Task<()>,
 1169    _scroll_cursor_center_top_bottom_task: Task<()>,
 1170    serialize_selections: Task<()>,
 1171    serialize_folds: Task<()>,
 1172    mouse_cursor_hidden: bool,
 1173    minimap: Option<Entity<Self>>,
 1174    hide_mouse_mode: HideMouseMode,
 1175    pub change_list: ChangeList,
 1176    inline_value_cache: InlineValueCache,
 1177    selection_drag_state: SelectionDragState,
 1178    next_color_inlay_id: usize,
 1179    colors: Option<LspColorData>,
 1180    folding_newlines: Task<()>,
 1181}
 1182
 1183#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1184enum NextScrollCursorCenterTopBottom {
 1185    #[default]
 1186    Center,
 1187    Top,
 1188    Bottom,
 1189}
 1190
 1191impl NextScrollCursorCenterTopBottom {
 1192    fn next(&self) -> Self {
 1193        match self {
 1194            Self::Center => Self::Top,
 1195            Self::Top => Self::Bottom,
 1196            Self::Bottom => Self::Center,
 1197        }
 1198    }
 1199}
 1200
 1201#[derive(Clone)]
 1202pub struct EditorSnapshot {
 1203    pub mode: EditorMode,
 1204    show_gutter: bool,
 1205    show_line_numbers: Option<bool>,
 1206    show_git_diff_gutter: Option<bool>,
 1207    show_code_actions: Option<bool>,
 1208    show_runnables: Option<bool>,
 1209    show_breakpoints: Option<bool>,
 1210    git_blame_gutter_max_author_length: Option<usize>,
 1211    pub display_snapshot: DisplaySnapshot,
 1212    pub placeholder_text: Option<Arc<str>>,
 1213    is_focused: bool,
 1214    scroll_anchor: ScrollAnchor,
 1215    ongoing_scroll: OngoingScroll,
 1216    current_line_highlight: CurrentLineHighlight,
 1217    gutter_hovered: bool,
 1218}
 1219
 1220#[derive(Default, Debug, Clone, Copy)]
 1221pub struct GutterDimensions {
 1222    pub left_padding: Pixels,
 1223    pub right_padding: Pixels,
 1224    pub width: Pixels,
 1225    pub margin: Pixels,
 1226    pub git_blame_entries_width: Option<Pixels>,
 1227}
 1228
 1229impl GutterDimensions {
 1230    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1231        Self {
 1232            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1233            ..Default::default()
 1234        }
 1235    }
 1236
 1237    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1238        -cx.text_system().descent(font_id, font_size)
 1239    }
 1240    /// The full width of the space taken up by the gutter.
 1241    pub fn full_width(&self) -> Pixels {
 1242        self.margin + self.width
 1243    }
 1244
 1245    /// The width of the space reserved for the fold indicators,
 1246    /// use alongside 'justify_end' and `gutter_width` to
 1247    /// right align content with the line numbers
 1248    pub fn fold_area_width(&self) -> Pixels {
 1249        self.margin + self.right_padding
 1250    }
 1251}
 1252
 1253struct CharacterDimensions {
 1254    em_width: Pixels,
 1255    em_advance: Pixels,
 1256    line_height: Pixels,
 1257}
 1258
 1259#[derive(Debug)]
 1260pub struct RemoteSelection {
 1261    pub replica_id: ReplicaId,
 1262    pub selection: Selection<Anchor>,
 1263    pub cursor_shape: CursorShape,
 1264    pub collaborator_id: CollaboratorId,
 1265    pub line_mode: bool,
 1266    pub user_name: Option<SharedString>,
 1267    pub color: PlayerColor,
 1268}
 1269
 1270#[derive(Clone, Debug)]
 1271struct SelectionHistoryEntry {
 1272    selections: Arc<[Selection<Anchor>]>,
 1273    select_next_state: Option<SelectNextState>,
 1274    select_prev_state: Option<SelectNextState>,
 1275    add_selections_state: Option<AddSelectionsState>,
 1276}
 1277
 1278#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1279enum SelectionHistoryMode {
 1280    Normal,
 1281    Undoing,
 1282    Redoing,
 1283    Skipping,
 1284}
 1285
 1286#[derive(Clone, PartialEq, Eq, Hash)]
 1287struct HoveredCursor {
 1288    replica_id: u16,
 1289    selection_id: usize,
 1290}
 1291
 1292impl Default for SelectionHistoryMode {
 1293    fn default() -> Self {
 1294        Self::Normal
 1295    }
 1296}
 1297
 1298#[derive(Debug)]
 1299/// SelectionEffects controls the side-effects of updating the selection.
 1300///
 1301/// The default behaviour does "what you mostly want":
 1302/// - it pushes to the nav history if the cursor moved by >10 lines
 1303/// - it re-triggers completion requests
 1304/// - it scrolls to fit
 1305///
 1306/// You might want to modify these behaviours. For example when doing a "jump"
 1307/// like go to definition, we always want to add to nav history; but when scrolling
 1308/// in vim mode we never do.
 1309///
 1310/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1311/// move.
 1312#[derive(Clone)]
 1313pub struct SelectionEffects {
 1314    nav_history: Option<bool>,
 1315    completions: bool,
 1316    scroll: Option<Autoscroll>,
 1317}
 1318
 1319impl Default for SelectionEffects {
 1320    fn default() -> Self {
 1321        Self {
 1322            nav_history: None,
 1323            completions: true,
 1324            scroll: Some(Autoscroll::fit()),
 1325        }
 1326    }
 1327}
 1328impl SelectionEffects {
 1329    pub fn scroll(scroll: Autoscroll) -> Self {
 1330        Self {
 1331            scroll: Some(scroll),
 1332            ..Default::default()
 1333        }
 1334    }
 1335
 1336    pub fn no_scroll() -> Self {
 1337        Self {
 1338            scroll: None,
 1339            ..Default::default()
 1340        }
 1341    }
 1342
 1343    pub fn completions(self, completions: bool) -> Self {
 1344        Self {
 1345            completions,
 1346            ..self
 1347        }
 1348    }
 1349
 1350    pub fn nav_history(self, nav_history: bool) -> Self {
 1351        Self {
 1352            nav_history: Some(nav_history),
 1353            ..self
 1354        }
 1355    }
 1356}
 1357
 1358struct DeferredSelectionEffectsState {
 1359    changed: bool,
 1360    effects: SelectionEffects,
 1361    old_cursor_position: Anchor,
 1362    history_entry: SelectionHistoryEntry,
 1363}
 1364
 1365#[derive(Default)]
 1366struct SelectionHistory {
 1367    #[allow(clippy::type_complexity)]
 1368    selections_by_transaction:
 1369        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1370    mode: SelectionHistoryMode,
 1371    undo_stack: VecDeque<SelectionHistoryEntry>,
 1372    redo_stack: VecDeque<SelectionHistoryEntry>,
 1373}
 1374
 1375impl SelectionHistory {
 1376    #[track_caller]
 1377    fn insert_transaction(
 1378        &mut self,
 1379        transaction_id: TransactionId,
 1380        selections: Arc<[Selection<Anchor>]>,
 1381    ) {
 1382        if selections.is_empty() {
 1383            log::error!(
 1384                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1385                std::panic::Location::caller()
 1386            );
 1387            return;
 1388        }
 1389        self.selections_by_transaction
 1390            .insert(transaction_id, (selections, None));
 1391    }
 1392
 1393    #[allow(clippy::type_complexity)]
 1394    fn transaction(
 1395        &self,
 1396        transaction_id: TransactionId,
 1397    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1398        self.selections_by_transaction.get(&transaction_id)
 1399    }
 1400
 1401    #[allow(clippy::type_complexity)]
 1402    fn transaction_mut(
 1403        &mut self,
 1404        transaction_id: TransactionId,
 1405    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1406        self.selections_by_transaction.get_mut(&transaction_id)
 1407    }
 1408
 1409    fn push(&mut self, entry: SelectionHistoryEntry) {
 1410        if !entry.selections.is_empty() {
 1411            match self.mode {
 1412                SelectionHistoryMode::Normal => {
 1413                    self.push_undo(entry);
 1414                    self.redo_stack.clear();
 1415                }
 1416                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1417                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1418                SelectionHistoryMode::Skipping => {}
 1419            }
 1420        }
 1421    }
 1422
 1423    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1424        if self
 1425            .undo_stack
 1426            .back()
 1427            .is_none_or(|e| e.selections != entry.selections)
 1428        {
 1429            self.undo_stack.push_back(entry);
 1430            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1431                self.undo_stack.pop_front();
 1432            }
 1433        }
 1434    }
 1435
 1436    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1437        if self
 1438            .redo_stack
 1439            .back()
 1440            .is_none_or(|e| e.selections != entry.selections)
 1441        {
 1442            self.redo_stack.push_back(entry);
 1443            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1444                self.redo_stack.pop_front();
 1445            }
 1446        }
 1447    }
 1448}
 1449
 1450#[derive(Clone, Copy)]
 1451pub struct RowHighlightOptions {
 1452    pub autoscroll: bool,
 1453    pub include_gutter: bool,
 1454}
 1455
 1456impl Default for RowHighlightOptions {
 1457    fn default() -> Self {
 1458        Self {
 1459            autoscroll: Default::default(),
 1460            include_gutter: true,
 1461        }
 1462    }
 1463}
 1464
 1465struct RowHighlight {
 1466    index: usize,
 1467    range: Range<Anchor>,
 1468    color: Hsla,
 1469    options: RowHighlightOptions,
 1470    type_id: TypeId,
 1471}
 1472
 1473#[derive(Clone, Debug)]
 1474struct AddSelectionsState {
 1475    groups: Vec<AddSelectionsGroup>,
 1476}
 1477
 1478#[derive(Clone, Debug)]
 1479struct AddSelectionsGroup {
 1480    above: bool,
 1481    stack: Vec<usize>,
 1482}
 1483
 1484#[derive(Clone)]
 1485struct SelectNextState {
 1486    query: AhoCorasick,
 1487    wordwise: bool,
 1488    done: bool,
 1489}
 1490
 1491impl std::fmt::Debug for SelectNextState {
 1492    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1493        f.debug_struct(std::any::type_name::<Self>())
 1494            .field("wordwise", &self.wordwise)
 1495            .field("done", &self.done)
 1496            .finish()
 1497    }
 1498}
 1499
 1500#[derive(Debug)]
 1501struct AutocloseRegion {
 1502    selection_id: usize,
 1503    range: Range<Anchor>,
 1504    pair: BracketPair,
 1505}
 1506
 1507#[derive(Debug)]
 1508struct SnippetState {
 1509    ranges: Vec<Vec<Range<Anchor>>>,
 1510    active_index: usize,
 1511    choices: Vec<Option<Vec<String>>>,
 1512}
 1513
 1514#[doc(hidden)]
 1515pub struct RenameState {
 1516    pub range: Range<Anchor>,
 1517    pub old_name: Arc<str>,
 1518    pub editor: Entity<Editor>,
 1519    block_id: CustomBlockId,
 1520}
 1521
 1522struct InvalidationStack<T>(Vec<T>);
 1523
 1524struct RegisteredEditPredictionProvider {
 1525    provider: Arc<dyn EditPredictionProviderHandle>,
 1526    _subscription: Subscription,
 1527}
 1528
 1529#[derive(Debug, PartialEq, Eq)]
 1530pub struct ActiveDiagnosticGroup {
 1531    pub active_range: Range<Anchor>,
 1532    pub active_message: String,
 1533    pub group_id: usize,
 1534    pub blocks: HashSet<CustomBlockId>,
 1535}
 1536
 1537#[derive(Debug, PartialEq, Eq)]
 1538
 1539pub(crate) enum ActiveDiagnostic {
 1540    None,
 1541    All,
 1542    Group(ActiveDiagnosticGroup),
 1543}
 1544
 1545#[derive(Serialize, Deserialize, Clone, Debug)]
 1546pub struct ClipboardSelection {
 1547    /// The number of bytes in this selection.
 1548    pub len: usize,
 1549    /// Whether this was a full-line selection.
 1550    pub is_entire_line: bool,
 1551    /// The indentation of the first line when this content was originally copied.
 1552    pub first_line_indent: u32,
 1553}
 1554
 1555// selections, scroll behavior, was newest selection reversed
 1556type SelectSyntaxNodeHistoryState = (
 1557    Box<[Selection<usize>]>,
 1558    SelectSyntaxNodeScrollBehavior,
 1559    bool,
 1560);
 1561
 1562#[derive(Default)]
 1563struct SelectSyntaxNodeHistory {
 1564    stack: Vec<SelectSyntaxNodeHistoryState>,
 1565    // disable temporarily to allow changing selections without losing the stack
 1566    pub disable_clearing: bool,
 1567}
 1568
 1569impl SelectSyntaxNodeHistory {
 1570    pub fn try_clear(&mut self) {
 1571        if !self.disable_clearing {
 1572            self.stack.clear();
 1573        }
 1574    }
 1575
 1576    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1577        self.stack.push(selection);
 1578    }
 1579
 1580    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1581        self.stack.pop()
 1582    }
 1583}
 1584
 1585enum SelectSyntaxNodeScrollBehavior {
 1586    CursorTop,
 1587    FitSelection,
 1588    CursorBottom,
 1589}
 1590
 1591#[derive(Debug)]
 1592pub(crate) struct NavigationData {
 1593    cursor_anchor: Anchor,
 1594    cursor_position: Point,
 1595    scroll_anchor: ScrollAnchor,
 1596    scroll_top_row: u32,
 1597}
 1598
 1599#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1600pub enum GotoDefinitionKind {
 1601    Symbol,
 1602    Declaration,
 1603    Type,
 1604    Implementation,
 1605}
 1606
 1607#[derive(Debug, Clone)]
 1608enum InlayHintRefreshReason {
 1609    ModifiersChanged(bool),
 1610    Toggle(bool),
 1611    SettingsChange(InlayHintSettings),
 1612    NewLinesShown,
 1613    BufferEdited(HashSet<Arc<Language>>),
 1614    RefreshRequested,
 1615    ExcerptsRemoved(Vec<ExcerptId>),
 1616}
 1617
 1618impl InlayHintRefreshReason {
 1619    fn description(&self) -> &'static str {
 1620        match self {
 1621            Self::ModifiersChanged(_) => "modifiers changed",
 1622            Self::Toggle(_) => "toggle",
 1623            Self::SettingsChange(_) => "settings change",
 1624            Self::NewLinesShown => "new lines shown",
 1625            Self::BufferEdited(_) => "buffer edited",
 1626            Self::RefreshRequested => "refresh requested",
 1627            Self::ExcerptsRemoved(_) => "excerpts removed",
 1628        }
 1629    }
 1630}
 1631
 1632pub enum FormatTarget {
 1633    Buffers(HashSet<Entity<Buffer>>),
 1634    Ranges(Vec<Range<MultiBufferPoint>>),
 1635}
 1636
 1637pub(crate) struct FocusedBlock {
 1638    id: BlockId,
 1639    focus_handle: WeakFocusHandle,
 1640}
 1641
 1642#[derive(Clone)]
 1643enum JumpData {
 1644    MultiBufferRow {
 1645        row: MultiBufferRow,
 1646        line_offset_from_top: u32,
 1647    },
 1648    MultiBufferPoint {
 1649        excerpt_id: ExcerptId,
 1650        position: Point,
 1651        anchor: text::Anchor,
 1652        line_offset_from_top: u32,
 1653    },
 1654}
 1655
 1656pub enum MultibufferSelectionMode {
 1657    First,
 1658    All,
 1659}
 1660
 1661#[derive(Clone, Copy, Debug, Default)]
 1662pub struct RewrapOptions {
 1663    pub override_language_settings: bool,
 1664    pub preserve_existing_whitespace: bool,
 1665}
 1666
 1667impl Editor {
 1668    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1669        let buffer = cx.new(|cx| Buffer::local("", cx));
 1670        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1671        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1672    }
 1673
 1674    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1675        let buffer = cx.new(|cx| Buffer::local("", cx));
 1676        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1677        Self::new(EditorMode::full(), buffer, None, window, cx)
 1678    }
 1679
 1680    pub fn auto_height(
 1681        min_lines: usize,
 1682        max_lines: usize,
 1683        window: &mut Window,
 1684        cx: &mut Context<Self>,
 1685    ) -> Self {
 1686        let buffer = cx.new(|cx| Buffer::local("", cx));
 1687        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1688        Self::new(
 1689            EditorMode::AutoHeight {
 1690                min_lines,
 1691                max_lines: Some(max_lines),
 1692            },
 1693            buffer,
 1694            None,
 1695            window,
 1696            cx,
 1697        )
 1698    }
 1699
 1700    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1701    /// The editor grows as tall as needed to fit its content.
 1702    pub fn auto_height_unbounded(
 1703        min_lines: usize,
 1704        window: &mut Window,
 1705        cx: &mut Context<Self>,
 1706    ) -> Self {
 1707        let buffer = cx.new(|cx| Buffer::local("", cx));
 1708        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1709        Self::new(
 1710            EditorMode::AutoHeight {
 1711                min_lines,
 1712                max_lines: None,
 1713            },
 1714            buffer,
 1715            None,
 1716            window,
 1717            cx,
 1718        )
 1719    }
 1720
 1721    pub fn for_buffer(
 1722        buffer: Entity<Buffer>,
 1723        project: Option<Entity<Project>>,
 1724        window: &mut Window,
 1725        cx: &mut Context<Self>,
 1726    ) -> Self {
 1727        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1728        Self::new(EditorMode::full(), buffer, project, window, cx)
 1729    }
 1730
 1731    pub fn for_multibuffer(
 1732        buffer: Entity<MultiBuffer>,
 1733        project: Option<Entity<Project>>,
 1734        window: &mut Window,
 1735        cx: &mut Context<Self>,
 1736    ) -> Self {
 1737        Self::new(EditorMode::full(), buffer, project, window, cx)
 1738    }
 1739
 1740    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1741        let mut clone = Self::new(
 1742            self.mode.clone(),
 1743            self.buffer.clone(),
 1744            self.project.clone(),
 1745            window,
 1746            cx,
 1747        );
 1748        self.display_map.update(cx, |display_map, cx| {
 1749            let snapshot = display_map.snapshot(cx);
 1750            clone.display_map.update(cx, |display_map, cx| {
 1751                display_map.set_state(&snapshot, cx);
 1752            });
 1753        });
 1754        clone.folds_did_change(cx);
 1755        clone.selections.clone_state(&self.selections);
 1756        clone.scroll_manager.clone_state(&self.scroll_manager);
 1757        clone.searchable = self.searchable;
 1758        clone.read_only = self.read_only;
 1759        clone
 1760    }
 1761
 1762    pub fn new(
 1763        mode: EditorMode,
 1764        buffer: Entity<MultiBuffer>,
 1765        project: Option<Entity<Project>>,
 1766        window: &mut Window,
 1767        cx: &mut Context<Self>,
 1768    ) -> Self {
 1769        Editor::new_internal(mode, buffer, project, None, window, cx)
 1770    }
 1771
 1772    fn new_internal(
 1773        mode: EditorMode,
 1774        buffer: Entity<MultiBuffer>,
 1775        project: Option<Entity<Project>>,
 1776        display_map: Option<Entity<DisplayMap>>,
 1777        window: &mut Window,
 1778        cx: &mut Context<Self>,
 1779    ) -> Self {
 1780        debug_assert!(
 1781            display_map.is_none() || mode.is_minimap(),
 1782            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1783        );
 1784
 1785        let full_mode = mode.is_full();
 1786        let is_minimap = mode.is_minimap();
 1787        let diagnostics_max_severity = if full_mode {
 1788            EditorSettings::get_global(cx)
 1789                .diagnostics_max_severity
 1790                .unwrap_or(DiagnosticSeverity::Hint)
 1791        } else {
 1792            DiagnosticSeverity::Off
 1793        };
 1794        let style = window.text_style();
 1795        let font_size = style.font_size.to_pixels(window.rem_size());
 1796        let editor = cx.entity().downgrade();
 1797        let fold_placeholder = FoldPlaceholder {
 1798            constrain_width: false,
 1799            render: Arc::new(move |fold_id, fold_range, cx| {
 1800                let editor = editor.clone();
 1801                div()
 1802                    .id(fold_id)
 1803                    .bg(cx.theme().colors().ghost_element_background)
 1804                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1805                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1806                    .rounded_xs()
 1807                    .size_full()
 1808                    .cursor_pointer()
 1809                    .child("")
 1810                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1811                    .on_click(move |_, _window, cx| {
 1812                        editor
 1813                            .update(cx, |editor, cx| {
 1814                                editor.unfold_ranges(
 1815                                    &[fold_range.start..fold_range.end],
 1816                                    true,
 1817                                    false,
 1818                                    cx,
 1819                                );
 1820                                cx.stop_propagation();
 1821                            })
 1822                            .ok();
 1823                    })
 1824                    .into_any()
 1825            }),
 1826            merge_adjacent: true,
 1827            ..FoldPlaceholder::default()
 1828        };
 1829        let display_map = display_map.unwrap_or_else(|| {
 1830            cx.new(|cx| {
 1831                DisplayMap::new(
 1832                    buffer.clone(),
 1833                    style.font(),
 1834                    font_size,
 1835                    None,
 1836                    FILE_HEADER_HEIGHT,
 1837                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1838                    fold_placeholder,
 1839                    diagnostics_max_severity,
 1840                    cx,
 1841                )
 1842            })
 1843        });
 1844
 1845        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1846
 1847        let blink_manager = cx.new(|cx| {
 1848            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1849            if is_minimap {
 1850                blink_manager.disable(cx);
 1851            }
 1852            blink_manager
 1853        });
 1854
 1855        let soft_wrap_mode_override =
 1856            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1857
 1858        let mut project_subscriptions = Vec::new();
 1859        if full_mode && let Some(project) = project.as_ref() {
 1860            project_subscriptions.push(cx.subscribe_in(
 1861                project,
 1862                window,
 1863                |editor, _, event, window, cx| match event {
 1864                    project::Event::RefreshCodeLens => {
 1865                        // we always query lens with actions, without storing them, always refreshing them
 1866                    }
 1867                    project::Event::RefreshInlayHints => {
 1868                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1869                    }
 1870                    project::Event::LanguageServerAdded(..)
 1871                    | project::Event::LanguageServerRemoved(..) => {
 1872                        if editor.tasks_update_task.is_none() {
 1873                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1874                        }
 1875                    }
 1876                    project::Event::SnippetEdit(id, snippet_edits) => {
 1877                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1878                            let focus_handle = editor.focus_handle(cx);
 1879                            if focus_handle.is_focused(window) {
 1880                                let snapshot = buffer.read(cx).snapshot();
 1881                                for (range, snippet) in snippet_edits {
 1882                                    let editor_range =
 1883                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1884                                    editor
 1885                                        .insert_snippet(
 1886                                            &[editor_range],
 1887                                            snippet.clone(),
 1888                                            window,
 1889                                            cx,
 1890                                        )
 1891                                        .ok();
 1892                                }
 1893                            }
 1894                        }
 1895                    }
 1896                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1897                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1898                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1899                        }
 1900                    }
 1901
 1902                    project::Event::EntryRenamed(transaction) => {
 1903                        let Some(workspace) = editor.workspace() else {
 1904                            return;
 1905                        };
 1906                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1907                        else {
 1908                            return;
 1909                        };
 1910                        if active_editor.entity_id() == cx.entity_id() {
 1911                            let edited_buffers_already_open = {
 1912                                let other_editors: Vec<Entity<Editor>> = workspace
 1913                                    .read(cx)
 1914                                    .panes()
 1915                                    .iter()
 1916                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1917                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1918                                    .collect();
 1919
 1920                                transaction.0.keys().all(|buffer| {
 1921                                    other_editors.iter().any(|editor| {
 1922                                        let multi_buffer = editor.read(cx).buffer();
 1923                                        multi_buffer.read(cx).is_singleton()
 1924                                            && multi_buffer.read(cx).as_singleton().map_or(
 1925                                                false,
 1926                                                |singleton| {
 1927                                                    singleton.entity_id() == buffer.entity_id()
 1928                                                },
 1929                                            )
 1930                                    })
 1931                                })
 1932                            };
 1933
 1934                            if !edited_buffers_already_open {
 1935                                let workspace = workspace.downgrade();
 1936                                let transaction = transaction.clone();
 1937                                cx.defer_in(window, move |_, window, cx| {
 1938                                    cx.spawn_in(window, async move |editor, cx| {
 1939                                        Self::open_project_transaction(
 1940                                            &editor,
 1941                                            workspace,
 1942                                            transaction,
 1943                                            "Rename".to_string(),
 1944                                            cx,
 1945                                        )
 1946                                        .await
 1947                                        .ok()
 1948                                    })
 1949                                    .detach();
 1950                                });
 1951                            }
 1952                        }
 1953                    }
 1954
 1955                    _ => {}
 1956                },
 1957            ));
 1958            if let Some(task_inventory) = project
 1959                .read(cx)
 1960                .task_store()
 1961                .read(cx)
 1962                .task_inventory()
 1963                .cloned()
 1964            {
 1965                project_subscriptions.push(cx.observe_in(
 1966                    &task_inventory,
 1967                    window,
 1968                    |editor, _, window, cx| {
 1969                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1970                    },
 1971                ));
 1972            };
 1973
 1974            project_subscriptions.push(cx.subscribe_in(
 1975                &project.read(cx).breakpoint_store(),
 1976                window,
 1977                |editor, _, event, window, cx| match event {
 1978                    BreakpointStoreEvent::ClearDebugLines => {
 1979                        editor.clear_row_highlights::<ActiveDebugLine>();
 1980                        editor.refresh_inline_values(cx);
 1981                    }
 1982                    BreakpointStoreEvent::SetDebugLine => {
 1983                        if editor.go_to_active_debug_line(window, cx) {
 1984                            cx.stop_propagation();
 1985                        }
 1986
 1987                        editor.refresh_inline_values(cx);
 1988                    }
 1989                    _ => {}
 1990                },
 1991            ));
 1992            let git_store = project.read(cx).git_store().clone();
 1993            let project = project.clone();
 1994            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1995                if let GitStoreEvent::RepositoryUpdated(
 1996                    _,
 1997                    RepositoryEvent::Updated {
 1998                        new_instance: true, ..
 1999                    },
 2000                    _,
 2001                ) = event
 2002                {
 2003                    this.load_diff_task = Some(
 2004                        update_uncommitted_diff_for_buffer(
 2005                            cx.entity(),
 2006                            &project,
 2007                            this.buffer.read(cx).all_buffers(),
 2008                            this.buffer.clone(),
 2009                            cx,
 2010                        )
 2011                        .shared(),
 2012                    );
 2013                }
 2014            }));
 2015        }
 2016
 2017        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2018
 2019        let inlay_hint_settings =
 2020            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2021        let focus_handle = cx.focus_handle();
 2022        if !is_minimap {
 2023            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2024                .detach();
 2025            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2026                .detach();
 2027            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2028                .detach();
 2029            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2030                .detach();
 2031            cx.observe_pending_input(window, Self::observe_pending_input)
 2032                .detach();
 2033        }
 2034
 2035        let show_indent_guides =
 2036            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2037                Some(false)
 2038            } else {
 2039                None
 2040            };
 2041
 2042        let breakpoint_store = match (&mode, project.as_ref()) {
 2043            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2044            _ => None,
 2045        };
 2046
 2047        let mut code_action_providers = Vec::new();
 2048        let mut load_uncommitted_diff = None;
 2049        if let Some(project) = project.clone() {
 2050            load_uncommitted_diff = Some(
 2051                update_uncommitted_diff_for_buffer(
 2052                    cx.entity(),
 2053                    &project,
 2054                    buffer.read(cx).all_buffers(),
 2055                    buffer.clone(),
 2056                    cx,
 2057                )
 2058                .shared(),
 2059            );
 2060            code_action_providers.push(Rc::new(project) as Rc<_>);
 2061        }
 2062
 2063        let mut editor = Self {
 2064            focus_handle,
 2065            show_cursor_when_unfocused: false,
 2066            last_focused_descendant: None,
 2067            buffer: buffer.clone(),
 2068            display_map: display_map.clone(),
 2069            selections,
 2070            scroll_manager: ScrollManager::new(cx),
 2071            columnar_selection_state: None,
 2072            add_selections_state: None,
 2073            select_next_state: None,
 2074            select_prev_state: None,
 2075            selection_history: SelectionHistory::default(),
 2076            defer_selection_effects: false,
 2077            deferred_selection_effects_state: None,
 2078            autoclose_regions: Vec::new(),
 2079            snippet_stack: InvalidationStack::default(),
 2080            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2081            ime_transaction: None,
 2082            active_diagnostics: ActiveDiagnostic::None,
 2083            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2084            inline_diagnostics_update: Task::ready(()),
 2085            inline_diagnostics: Vec::new(),
 2086            soft_wrap_mode_override,
 2087            diagnostics_max_severity,
 2088            hard_wrap: None,
 2089            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2090            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2091            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2092            project,
 2093            blink_manager: blink_manager.clone(),
 2094            show_local_selections: true,
 2095            show_scrollbars: ScrollbarAxes {
 2096                horizontal: full_mode,
 2097                vertical: full_mode,
 2098            },
 2099            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2100            offset_content: !matches!(mode, EditorMode::SingleLine),
 2101            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2102            show_gutter: full_mode,
 2103            show_line_numbers: (!full_mode).then_some(false),
 2104            use_relative_line_numbers: None,
 2105            disable_expand_excerpt_buttons: !full_mode,
 2106            show_git_diff_gutter: None,
 2107            show_code_actions: None,
 2108            show_runnables: None,
 2109            show_breakpoints: None,
 2110            show_wrap_guides: None,
 2111            show_indent_guides,
 2112            placeholder_text: None,
 2113            highlight_order: 0,
 2114            highlighted_rows: HashMap::default(),
 2115            background_highlights: HashMap::default(),
 2116            gutter_highlights: HashMap::default(),
 2117            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2118            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2119            nav_history: None,
 2120            context_menu: RefCell::new(None),
 2121            context_menu_options: None,
 2122            mouse_context_menu: None,
 2123            completion_tasks: Vec::new(),
 2124            inline_blame_popover: None,
 2125            inline_blame_popover_show_task: None,
 2126            signature_help_state: SignatureHelpState::default(),
 2127            auto_signature_help: None,
 2128            find_all_references_task_sources: Vec::new(),
 2129            next_completion_id: 0,
 2130            next_inlay_id: 0,
 2131            code_action_providers,
 2132            available_code_actions: None,
 2133            code_actions_task: None,
 2134            quick_selection_highlight_task: None,
 2135            debounced_selection_highlight_task: None,
 2136            document_highlights_task: None,
 2137            linked_editing_range_task: None,
 2138            pending_rename: None,
 2139            searchable: !is_minimap,
 2140            cursor_shape: EditorSettings::get_global(cx)
 2141                .cursor_shape
 2142                .unwrap_or_default(),
 2143            current_line_highlight: None,
 2144            autoindent_mode: Some(AutoindentMode::EachLine),
 2145            collapse_matches: false,
 2146            workspace: None,
 2147            input_enabled: !is_minimap,
 2148            use_modal_editing: full_mode,
 2149            read_only: is_minimap,
 2150            use_autoclose: true,
 2151            use_auto_surround: true,
 2152            auto_replace_emoji_shortcode: false,
 2153            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2154            leader_id: None,
 2155            remote_id: None,
 2156            hover_state: HoverState::default(),
 2157            pending_mouse_down: None,
 2158            hovered_link_state: None,
 2159            edit_prediction_provider: None,
 2160            active_edit_prediction: None,
 2161            stale_edit_prediction_in_menu: None,
 2162            edit_prediction_preview: EditPredictionPreview::Inactive {
 2163                released_too_fast: false,
 2164            },
 2165            inline_diagnostics_enabled: full_mode,
 2166            diagnostics_enabled: full_mode,
 2167            word_completions_enabled: full_mode,
 2168            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2169            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2170            gutter_hovered: false,
 2171            pixel_position_of_newest_cursor: None,
 2172            last_bounds: None,
 2173            last_position_map: None,
 2174            expect_bounds_change: None,
 2175            gutter_dimensions: GutterDimensions::default(),
 2176            style: None,
 2177            show_cursor_names: false,
 2178            hovered_cursors: HashMap::default(),
 2179            next_editor_action_id: EditorActionId::default(),
 2180            editor_actions: Rc::default(),
 2181            edit_predictions_hidden_for_vim_mode: false,
 2182            show_edit_predictions_override: None,
 2183            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2184            edit_prediction_settings: EditPredictionSettings::Disabled,
 2185            edit_prediction_indent_conflict: false,
 2186            edit_prediction_requires_modifier_in_indent_conflict: true,
 2187            custom_context_menu: None,
 2188            show_git_blame_gutter: false,
 2189            show_git_blame_inline: false,
 2190            show_selection_menu: None,
 2191            show_git_blame_inline_delay_task: None,
 2192            git_blame_inline_enabled: full_mode
 2193                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2194            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2195            serialize_dirty_buffers: !is_minimap
 2196                && ProjectSettings::get_global(cx)
 2197                    .session
 2198                    .restore_unsaved_buffers,
 2199            blame: None,
 2200            blame_subscription: None,
 2201            tasks: BTreeMap::default(),
 2202
 2203            breakpoint_store,
 2204            gutter_breakpoint_indicator: (None, None),
 2205            hovered_diff_hunk_row: None,
 2206            _subscriptions: (!is_minimap)
 2207                .then(|| {
 2208                    vec![
 2209                        cx.observe(&buffer, Self::on_buffer_changed),
 2210                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2211                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2212                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2213                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2214                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2215                        cx.observe_window_activation(window, |editor, window, cx| {
 2216                            let active = window.is_window_active();
 2217                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2218                                if active {
 2219                                    blink_manager.enable(cx);
 2220                                } else {
 2221                                    blink_manager.disable(cx);
 2222                                }
 2223                            });
 2224                            if active {
 2225                                editor.show_mouse_cursor(cx);
 2226                            }
 2227                        }),
 2228                    ]
 2229                })
 2230                .unwrap_or_default(),
 2231            tasks_update_task: None,
 2232            pull_diagnostics_task: Task::ready(()),
 2233            colors: None,
 2234            next_color_inlay_id: 0,
 2235            linked_edit_ranges: Default::default(),
 2236            in_project_search: false,
 2237            previous_search_ranges: None,
 2238            breadcrumb_header: None,
 2239            focused_block: None,
 2240            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2241            addons: HashMap::default(),
 2242            registered_buffers: HashMap::default(),
 2243            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2244            selection_mark_mode: false,
 2245            toggle_fold_multiple_buffers: Task::ready(()),
 2246            serialize_selections: Task::ready(()),
 2247            serialize_folds: Task::ready(()),
 2248            text_style_refinement: None,
 2249            load_diff_task: load_uncommitted_diff,
 2250            temporary_diff_override: false,
 2251            mouse_cursor_hidden: false,
 2252            minimap: None,
 2253            hide_mouse_mode: EditorSettings::get_global(cx)
 2254                .hide_mouse
 2255                .unwrap_or_default(),
 2256            change_list: ChangeList::new(),
 2257            mode,
 2258            selection_drag_state: SelectionDragState::None,
 2259            folding_newlines: Task::ready(()),
 2260        };
 2261
 2262        if is_minimap {
 2263            return editor;
 2264        }
 2265
 2266        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2267            editor
 2268                ._subscriptions
 2269                .push(cx.observe(breakpoints, |_, _, cx| {
 2270                    cx.notify();
 2271                }));
 2272        }
 2273        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2274        editor._subscriptions.extend(project_subscriptions);
 2275
 2276        editor._subscriptions.push(cx.subscribe_in(
 2277            &cx.entity(),
 2278            window,
 2279            |editor, _, e: &EditorEvent, window, cx| match e {
 2280                EditorEvent::ScrollPositionChanged { local, .. } => {
 2281                    if *local {
 2282                        let new_anchor = editor.scroll_manager.anchor();
 2283                        let snapshot = editor.snapshot(window, cx);
 2284                        editor.update_restoration_data(cx, move |data| {
 2285                            data.scroll_position = (
 2286                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2287                                new_anchor.offset,
 2288                            );
 2289                        });
 2290                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2291                        editor.inline_blame_popover.take();
 2292                    }
 2293                }
 2294                EditorEvent::Edited { .. } => {
 2295                    if !vim_enabled(cx) {
 2296                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2297                        let pop_state = editor
 2298                            .change_list
 2299                            .last()
 2300                            .map(|previous| {
 2301                                previous.len() == selections.len()
 2302                                    && previous.iter().enumerate().all(|(ix, p)| {
 2303                                        p.to_display_point(&map).row()
 2304                                            == selections[ix].head().row()
 2305                                    })
 2306                            })
 2307                            .unwrap_or(false);
 2308                        let new_positions = selections
 2309                            .into_iter()
 2310                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2311                            .collect();
 2312                        editor
 2313                            .change_list
 2314                            .push_to_change_list(pop_state, new_positions);
 2315                    }
 2316                }
 2317                _ => (),
 2318            },
 2319        ));
 2320
 2321        if let Some(dap_store) = editor
 2322            .project
 2323            .as_ref()
 2324            .map(|project| project.read(cx).dap_store())
 2325        {
 2326            let weak_editor = cx.weak_entity();
 2327
 2328            editor
 2329                ._subscriptions
 2330                .push(
 2331                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2332                        let session_entity = cx.entity();
 2333                        weak_editor
 2334                            .update(cx, |editor, cx| {
 2335                                editor._subscriptions.push(
 2336                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2337                                );
 2338                            })
 2339                            .ok();
 2340                    }),
 2341                );
 2342
 2343            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2344                editor
 2345                    ._subscriptions
 2346                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2347            }
 2348        }
 2349
 2350        // skip adding the initial selection to selection history
 2351        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2352        editor.end_selection(window, cx);
 2353        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2354
 2355        editor.scroll_manager.show_scrollbars(window, cx);
 2356        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2357
 2358        if full_mode {
 2359            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2360            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2361
 2362            if editor.git_blame_inline_enabled {
 2363                editor.start_git_blame_inline(false, window, cx);
 2364            }
 2365
 2366            editor.go_to_active_debug_line(window, cx);
 2367
 2368            if let Some(buffer) = buffer.read(cx).as_singleton()
 2369                && let Some(project) = editor.project()
 2370            {
 2371                let handle = project.update(cx, |project, cx| {
 2372                    project.register_buffer_with_language_servers(&buffer, cx)
 2373                });
 2374                editor
 2375                    .registered_buffers
 2376                    .insert(buffer.read(cx).remote_id(), handle);
 2377            }
 2378
 2379            editor.minimap =
 2380                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2381            editor.colors = Some(LspColorData::new(cx));
 2382            editor.update_lsp_data(false, None, window, cx);
 2383        }
 2384
 2385        if editor.mode.is_full() {
 2386            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2387        }
 2388
 2389        editor
 2390    }
 2391
 2392    pub fn deploy_mouse_context_menu(
 2393        &mut self,
 2394        position: gpui::Point<Pixels>,
 2395        context_menu: Entity<ContextMenu>,
 2396        window: &mut Window,
 2397        cx: &mut Context<Self>,
 2398    ) {
 2399        self.mouse_context_menu = Some(MouseContextMenu::new(
 2400            self,
 2401            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2402            context_menu,
 2403            window,
 2404            cx,
 2405        ));
 2406    }
 2407
 2408    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2409        self.mouse_context_menu
 2410            .as_ref()
 2411            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2412    }
 2413
 2414    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2415        if self
 2416            .selections
 2417            .pending
 2418            .as_ref()
 2419            .is_some_and(|pending_selection| {
 2420                let snapshot = self.buffer().read(cx).snapshot(cx);
 2421                pending_selection
 2422                    .selection
 2423                    .range()
 2424                    .includes(range, &snapshot)
 2425            })
 2426        {
 2427            return true;
 2428        }
 2429
 2430        self.selections
 2431            .disjoint_in_range::<usize>(range.clone(), cx)
 2432            .into_iter()
 2433            .any(|selection| {
 2434                // This is needed to cover a corner case, if we just check for an existing
 2435                // selection in the fold range, having a cursor at the start of the fold
 2436                // marks it as selected. Non-empty selections don't cause this.
 2437                let length = selection.end - selection.start;
 2438                length > 0
 2439            })
 2440    }
 2441
 2442    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2443        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2444    }
 2445
 2446    fn key_context_internal(
 2447        &self,
 2448        has_active_edit_prediction: bool,
 2449        window: &Window,
 2450        cx: &App,
 2451    ) -> KeyContext {
 2452        let mut key_context = KeyContext::new_with_defaults();
 2453        key_context.add("Editor");
 2454        let mode = match self.mode {
 2455            EditorMode::SingleLine => "single_line",
 2456            EditorMode::AutoHeight { .. } => "auto_height",
 2457            EditorMode::Minimap { .. } => "minimap",
 2458            EditorMode::Full { .. } => "full",
 2459        };
 2460
 2461        if EditorSettings::jupyter_enabled(cx) {
 2462            key_context.add("jupyter");
 2463        }
 2464
 2465        key_context.set("mode", mode);
 2466        if self.pending_rename.is_some() {
 2467            key_context.add("renaming");
 2468        }
 2469
 2470        match self.context_menu.borrow().as_ref() {
 2471            Some(CodeContextMenu::Completions(menu)) => {
 2472                if menu.visible() {
 2473                    key_context.add("menu");
 2474                    key_context.add("showing_completions");
 2475                }
 2476            }
 2477            Some(CodeContextMenu::CodeActions(menu)) => {
 2478                if menu.visible() {
 2479                    key_context.add("menu");
 2480                    key_context.add("showing_code_actions")
 2481                }
 2482            }
 2483            None => {}
 2484        }
 2485
 2486        if self.signature_help_state.has_multiple_signatures() {
 2487            key_context.add("showing_signature_help");
 2488        }
 2489
 2490        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2491        if !self.focus_handle(cx).contains_focused(window, cx)
 2492            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2493        {
 2494            for addon in self.addons.values() {
 2495                addon.extend_key_context(&mut key_context, cx)
 2496            }
 2497        }
 2498
 2499        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2500            if let Some(extension) = singleton_buffer
 2501                .read(cx)
 2502                .file()
 2503                .and_then(|file| file.path().extension()?.to_str())
 2504            {
 2505                key_context.set("extension", extension.to_string());
 2506            }
 2507        } else {
 2508            key_context.add("multibuffer");
 2509        }
 2510
 2511        if has_active_edit_prediction {
 2512            if self.edit_prediction_in_conflict() {
 2513                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2514            } else {
 2515                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2516                key_context.add("copilot_suggestion");
 2517            }
 2518        }
 2519
 2520        if self.selection_mark_mode {
 2521            key_context.add("selection_mode");
 2522        }
 2523
 2524        key_context
 2525    }
 2526
 2527    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2528        if self.mouse_cursor_hidden {
 2529            self.mouse_cursor_hidden = false;
 2530            cx.notify();
 2531        }
 2532    }
 2533
 2534    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2535        let hide_mouse_cursor = match origin {
 2536            HideMouseCursorOrigin::TypingAction => {
 2537                matches!(
 2538                    self.hide_mouse_mode,
 2539                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2540                )
 2541            }
 2542            HideMouseCursorOrigin::MovementAction => {
 2543                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2544            }
 2545        };
 2546        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2547            self.mouse_cursor_hidden = hide_mouse_cursor;
 2548            cx.notify();
 2549        }
 2550    }
 2551
 2552    pub fn edit_prediction_in_conflict(&self) -> bool {
 2553        if !self.show_edit_predictions_in_menu() {
 2554            return false;
 2555        }
 2556
 2557        let showing_completions = self
 2558            .context_menu
 2559            .borrow()
 2560            .as_ref()
 2561            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2562
 2563        showing_completions
 2564            || self.edit_prediction_requires_modifier()
 2565            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2566            // bindings to insert tab characters.
 2567            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2568    }
 2569
 2570    pub fn accept_edit_prediction_keybind(
 2571        &self,
 2572        accept_partial: bool,
 2573        window: &Window,
 2574        cx: &App,
 2575    ) -> AcceptEditPredictionBinding {
 2576        let key_context = self.key_context_internal(true, window, cx);
 2577        let in_conflict = self.edit_prediction_in_conflict();
 2578
 2579        let bindings = if accept_partial {
 2580            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2581        } else {
 2582            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2583        };
 2584
 2585        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2586        // just the first one.
 2587        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2588            !in_conflict
 2589                || binding
 2590                    .keystrokes()
 2591                    .first()
 2592                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2593        }))
 2594    }
 2595
 2596    pub fn new_file(
 2597        workspace: &mut Workspace,
 2598        _: &workspace::NewFile,
 2599        window: &mut Window,
 2600        cx: &mut Context<Workspace>,
 2601    ) {
 2602        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2603            "Failed to create buffer",
 2604            window,
 2605            cx,
 2606            |e, _, _| match e.error_code() {
 2607                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2608                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2609                e.error_tag("required").unwrap_or("the latest version")
 2610            )),
 2611                _ => None,
 2612            },
 2613        );
 2614    }
 2615
 2616    pub fn new_in_workspace(
 2617        workspace: &mut Workspace,
 2618        window: &mut Window,
 2619        cx: &mut Context<Workspace>,
 2620    ) -> Task<Result<Entity<Editor>>> {
 2621        let project = workspace.project().clone();
 2622        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2623
 2624        cx.spawn_in(window, async move |workspace, cx| {
 2625            let buffer = create.await?;
 2626            workspace.update_in(cx, |workspace, window, cx| {
 2627                let editor =
 2628                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2629                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2630                editor
 2631            })
 2632        })
 2633    }
 2634
 2635    fn new_file_vertical(
 2636        workspace: &mut Workspace,
 2637        _: &workspace::NewFileSplitVertical,
 2638        window: &mut Window,
 2639        cx: &mut Context<Workspace>,
 2640    ) {
 2641        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2642    }
 2643
 2644    fn new_file_horizontal(
 2645        workspace: &mut Workspace,
 2646        _: &workspace::NewFileSplitHorizontal,
 2647        window: &mut Window,
 2648        cx: &mut Context<Workspace>,
 2649    ) {
 2650        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2651    }
 2652
 2653    fn new_file_in_direction(
 2654        workspace: &mut Workspace,
 2655        direction: SplitDirection,
 2656        window: &mut Window,
 2657        cx: &mut Context<Workspace>,
 2658    ) {
 2659        let project = workspace.project().clone();
 2660        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2661
 2662        cx.spawn_in(window, async move |workspace, cx| {
 2663            let buffer = create.await?;
 2664            workspace.update_in(cx, move |workspace, window, cx| {
 2665                workspace.split_item(
 2666                    direction,
 2667                    Box::new(
 2668                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2669                    ),
 2670                    window,
 2671                    cx,
 2672                )
 2673            })?;
 2674            anyhow::Ok(())
 2675        })
 2676        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2677            match e.error_code() {
 2678                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2679                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2680                e.error_tag("required").unwrap_or("the latest version")
 2681            )),
 2682                _ => None,
 2683            }
 2684        });
 2685    }
 2686
 2687    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2688        self.leader_id
 2689    }
 2690
 2691    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2692        &self.buffer
 2693    }
 2694
 2695    pub fn project(&self) -> Option<&Entity<Project>> {
 2696        self.project.as_ref()
 2697    }
 2698
 2699    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2700        self.workspace.as_ref()?.0.upgrade()
 2701    }
 2702
 2703    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2704        self.buffer().read(cx).title(cx)
 2705    }
 2706
 2707    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2708        let git_blame_gutter_max_author_length = self
 2709            .render_git_blame_gutter(cx)
 2710            .then(|| {
 2711                if let Some(blame) = self.blame.as_ref() {
 2712                    let max_author_length =
 2713                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2714                    Some(max_author_length)
 2715                } else {
 2716                    None
 2717                }
 2718            })
 2719            .flatten();
 2720
 2721        EditorSnapshot {
 2722            mode: self.mode.clone(),
 2723            show_gutter: self.show_gutter,
 2724            show_line_numbers: self.show_line_numbers,
 2725            show_git_diff_gutter: self.show_git_diff_gutter,
 2726            show_code_actions: self.show_code_actions,
 2727            show_runnables: self.show_runnables,
 2728            show_breakpoints: self.show_breakpoints,
 2729            git_blame_gutter_max_author_length,
 2730            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2731            scroll_anchor: self.scroll_manager.anchor(),
 2732            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2733            placeholder_text: self.placeholder_text.clone(),
 2734            is_focused: self.focus_handle.is_focused(window),
 2735            current_line_highlight: self
 2736                .current_line_highlight
 2737                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2738            gutter_hovered: self.gutter_hovered,
 2739        }
 2740    }
 2741
 2742    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2743        self.buffer.read(cx).language_at(point, cx)
 2744    }
 2745
 2746    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2747        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2748    }
 2749
 2750    pub fn active_excerpt(
 2751        &self,
 2752        cx: &App,
 2753    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2754        self.buffer
 2755            .read(cx)
 2756            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2757    }
 2758
 2759    pub fn mode(&self) -> &EditorMode {
 2760        &self.mode
 2761    }
 2762
 2763    pub fn set_mode(&mut self, mode: EditorMode) {
 2764        self.mode = mode;
 2765    }
 2766
 2767    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2768        self.collaboration_hub.as_deref()
 2769    }
 2770
 2771    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2772        self.collaboration_hub = Some(hub);
 2773    }
 2774
 2775    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2776        self.in_project_search = in_project_search;
 2777    }
 2778
 2779    pub fn set_custom_context_menu(
 2780        &mut self,
 2781        f: impl 'static
 2782        + Fn(
 2783            &mut Self,
 2784            DisplayPoint,
 2785            &mut Window,
 2786            &mut Context<Self>,
 2787        ) -> Option<Entity<ui::ContextMenu>>,
 2788    ) {
 2789        self.custom_context_menu = Some(Box::new(f))
 2790    }
 2791
 2792    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2793        self.completion_provider = provider;
 2794    }
 2795
 2796    #[cfg(any(test, feature = "test-support"))]
 2797    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2798        self.completion_provider.clone()
 2799    }
 2800
 2801    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2802        self.semantics_provider.clone()
 2803    }
 2804
 2805    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2806        self.semantics_provider = provider;
 2807    }
 2808
 2809    pub fn set_edit_prediction_provider<T>(
 2810        &mut self,
 2811        provider: Option<Entity<T>>,
 2812        window: &mut Window,
 2813        cx: &mut Context<Self>,
 2814    ) where
 2815        T: EditPredictionProvider,
 2816    {
 2817        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2818            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2819                if this.focus_handle.is_focused(window) {
 2820                    this.update_visible_edit_prediction(window, cx);
 2821                }
 2822            }),
 2823            provider: Arc::new(provider),
 2824        });
 2825        self.update_edit_prediction_settings(cx);
 2826        self.refresh_edit_prediction(false, false, window, cx);
 2827    }
 2828
 2829    pub fn placeholder_text(&self) -> Option<&str> {
 2830        self.placeholder_text.as_deref()
 2831    }
 2832
 2833    pub fn set_placeholder_text(
 2834        &mut self,
 2835        placeholder_text: impl Into<Arc<str>>,
 2836        cx: &mut Context<Self>,
 2837    ) {
 2838        let placeholder_text = Some(placeholder_text.into());
 2839        if self.placeholder_text != placeholder_text {
 2840            self.placeholder_text = placeholder_text;
 2841            cx.notify();
 2842        }
 2843    }
 2844
 2845    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2846        self.cursor_shape = cursor_shape;
 2847
 2848        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2849        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2850
 2851        cx.notify();
 2852    }
 2853
 2854    pub fn set_current_line_highlight(
 2855        &mut self,
 2856        current_line_highlight: Option<CurrentLineHighlight>,
 2857    ) {
 2858        self.current_line_highlight = current_line_highlight;
 2859    }
 2860
 2861    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2862        self.collapse_matches = collapse_matches;
 2863    }
 2864
 2865    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2866        let buffers = self.buffer.read(cx).all_buffers();
 2867        let Some(project) = self.project.as_ref() else {
 2868            return;
 2869        };
 2870        project.update(cx, |project, cx| {
 2871            for buffer in buffers {
 2872                self.registered_buffers
 2873                    .entry(buffer.read(cx).remote_id())
 2874                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2875            }
 2876        })
 2877    }
 2878
 2879    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2880        if self.collapse_matches {
 2881            return range.start..range.start;
 2882        }
 2883        range.clone()
 2884    }
 2885
 2886    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2887        if self.display_map.read(cx).clip_at_line_ends != clip {
 2888            self.display_map
 2889                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2890        }
 2891    }
 2892
 2893    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2894        self.input_enabled = input_enabled;
 2895    }
 2896
 2897    pub fn set_edit_predictions_hidden_for_vim_mode(
 2898        &mut self,
 2899        hidden: bool,
 2900        window: &mut Window,
 2901        cx: &mut Context<Self>,
 2902    ) {
 2903        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2904            self.edit_predictions_hidden_for_vim_mode = hidden;
 2905            if hidden {
 2906                self.update_visible_edit_prediction(window, cx);
 2907            } else {
 2908                self.refresh_edit_prediction(true, false, window, cx);
 2909            }
 2910        }
 2911    }
 2912
 2913    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2914        self.menu_edit_predictions_policy = value;
 2915    }
 2916
 2917    pub fn set_autoindent(&mut self, autoindent: bool) {
 2918        if autoindent {
 2919            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2920        } else {
 2921            self.autoindent_mode = None;
 2922        }
 2923    }
 2924
 2925    pub fn read_only(&self, cx: &App) -> bool {
 2926        self.read_only || self.buffer.read(cx).read_only()
 2927    }
 2928
 2929    pub fn set_read_only(&mut self, read_only: bool) {
 2930        self.read_only = read_only;
 2931    }
 2932
 2933    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2934        self.use_autoclose = autoclose;
 2935    }
 2936
 2937    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2938        self.use_auto_surround = auto_surround;
 2939    }
 2940
 2941    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2942        self.auto_replace_emoji_shortcode = auto_replace;
 2943    }
 2944
 2945    pub fn toggle_edit_predictions(
 2946        &mut self,
 2947        _: &ToggleEditPrediction,
 2948        window: &mut Window,
 2949        cx: &mut Context<Self>,
 2950    ) {
 2951        if self.show_edit_predictions_override.is_some() {
 2952            self.set_show_edit_predictions(None, window, cx);
 2953        } else {
 2954            let show_edit_predictions = !self.edit_predictions_enabled();
 2955            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2956        }
 2957    }
 2958
 2959    pub fn set_show_edit_predictions(
 2960        &mut self,
 2961        show_edit_predictions: Option<bool>,
 2962        window: &mut Window,
 2963        cx: &mut Context<Self>,
 2964    ) {
 2965        self.show_edit_predictions_override = show_edit_predictions;
 2966        self.update_edit_prediction_settings(cx);
 2967
 2968        if let Some(false) = show_edit_predictions {
 2969            self.discard_edit_prediction(false, cx);
 2970        } else {
 2971            self.refresh_edit_prediction(false, true, window, cx);
 2972        }
 2973    }
 2974
 2975    fn edit_predictions_disabled_in_scope(
 2976        &self,
 2977        buffer: &Entity<Buffer>,
 2978        buffer_position: language::Anchor,
 2979        cx: &App,
 2980    ) -> bool {
 2981        let snapshot = buffer.read(cx).snapshot();
 2982        let settings = snapshot.settings_at(buffer_position, cx);
 2983
 2984        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2985            return false;
 2986        };
 2987
 2988        scope.override_name().is_some_and(|scope_name| {
 2989            settings
 2990                .edit_predictions_disabled_in
 2991                .iter()
 2992                .any(|s| s == scope_name)
 2993        })
 2994    }
 2995
 2996    pub fn set_use_modal_editing(&mut self, to: bool) {
 2997        self.use_modal_editing = to;
 2998    }
 2999
 3000    pub fn use_modal_editing(&self) -> bool {
 3001        self.use_modal_editing
 3002    }
 3003
 3004    fn selections_did_change(
 3005        &mut self,
 3006        local: bool,
 3007        old_cursor_position: &Anchor,
 3008        effects: SelectionEffects,
 3009        window: &mut Window,
 3010        cx: &mut Context<Self>,
 3011    ) {
 3012        window.invalidate_character_coordinates();
 3013
 3014        // Copy selections to primary selection buffer
 3015        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3016        if local {
 3017            let selections = self.selections.all::<usize>(cx);
 3018            let buffer_handle = self.buffer.read(cx).read(cx);
 3019
 3020            let mut text = String::new();
 3021            for (index, selection) in selections.iter().enumerate() {
 3022                let text_for_selection = buffer_handle
 3023                    .text_for_range(selection.start..selection.end)
 3024                    .collect::<String>();
 3025
 3026                text.push_str(&text_for_selection);
 3027                if index != selections.len() - 1 {
 3028                    text.push('\n');
 3029                }
 3030            }
 3031
 3032            if !text.is_empty() {
 3033                cx.write_to_primary(ClipboardItem::new_string(text));
 3034            }
 3035        }
 3036
 3037        let selection_anchors = self.selections.disjoint_anchors();
 3038
 3039        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3040            self.buffer.update(cx, |buffer, cx| {
 3041                buffer.set_active_selections(
 3042                    &selection_anchors,
 3043                    self.selections.line_mode,
 3044                    self.cursor_shape,
 3045                    cx,
 3046                )
 3047            });
 3048        }
 3049        let display_map = self
 3050            .display_map
 3051            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3052        let buffer = &display_map.buffer_snapshot;
 3053        if self.selections.count() == 1 {
 3054            self.add_selections_state = None;
 3055        }
 3056        self.select_next_state = None;
 3057        self.select_prev_state = None;
 3058        self.select_syntax_node_history.try_clear();
 3059        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3060        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3061        self.take_rename(false, window, cx);
 3062
 3063        let newest_selection = self.selections.newest_anchor();
 3064        let new_cursor_position = newest_selection.head();
 3065        let selection_start = newest_selection.start;
 3066
 3067        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3068            self.push_to_nav_history(
 3069                *old_cursor_position,
 3070                Some(new_cursor_position.to_point(buffer)),
 3071                false,
 3072                effects.nav_history == Some(true),
 3073                cx,
 3074            );
 3075        }
 3076
 3077        if local {
 3078            if let Some(buffer_id) = new_cursor_position.buffer_id
 3079                && !self.registered_buffers.contains_key(&buffer_id)
 3080                && let Some(project) = self.project.as_ref()
 3081            {
 3082                project.update(cx, |project, cx| {
 3083                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3084                        return;
 3085                    };
 3086                    self.registered_buffers.insert(
 3087                        buffer_id,
 3088                        project.register_buffer_with_language_servers(&buffer, cx),
 3089                    );
 3090                })
 3091            }
 3092
 3093            let mut context_menu = self.context_menu.borrow_mut();
 3094            let completion_menu = match context_menu.as_ref() {
 3095                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3096                Some(CodeContextMenu::CodeActions(_)) => {
 3097                    *context_menu = None;
 3098                    None
 3099                }
 3100                None => None,
 3101            };
 3102            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3103            drop(context_menu);
 3104
 3105            if effects.completions
 3106                && let Some(completion_position) = completion_position
 3107            {
 3108                let start_offset = selection_start.to_offset(buffer);
 3109                let position_matches = start_offset == completion_position.to_offset(buffer);
 3110                let continue_showing = if position_matches {
 3111                    if self.snippet_stack.is_empty() {
 3112                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3113                    } else {
 3114                        // Snippet choices can be shown even when the cursor is in whitespace.
 3115                        // Dismissing the menu with actions like backspace is handled by
 3116                        // invalidation regions.
 3117                        true
 3118                    }
 3119                } else {
 3120                    false
 3121                };
 3122
 3123                if continue_showing {
 3124                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3125                } else {
 3126                    self.hide_context_menu(window, cx);
 3127                }
 3128            }
 3129
 3130            hide_hover(self, cx);
 3131
 3132            if old_cursor_position.to_display_point(&display_map).row()
 3133                != new_cursor_position.to_display_point(&display_map).row()
 3134            {
 3135                self.available_code_actions.take();
 3136            }
 3137            self.refresh_code_actions(window, cx);
 3138            self.refresh_document_highlights(cx);
 3139            self.refresh_selected_text_highlights(false, window, cx);
 3140            refresh_matching_bracket_highlights(self, window, cx);
 3141            self.update_visible_edit_prediction(window, cx);
 3142            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3143            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3144            self.inline_blame_popover.take();
 3145            if self.git_blame_inline_enabled {
 3146                self.start_inline_blame_timer(window, cx);
 3147            }
 3148        }
 3149
 3150        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3151        cx.emit(EditorEvent::SelectionsChanged { local });
 3152
 3153        let selections = &self.selections.disjoint;
 3154        if selections.len() == 1 {
 3155            cx.emit(SearchEvent::ActiveMatchChanged)
 3156        }
 3157        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3158            let inmemory_selections = selections
 3159                .iter()
 3160                .map(|s| {
 3161                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3162                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3163                })
 3164                .collect();
 3165            self.update_restoration_data(cx, |data| {
 3166                data.selections = inmemory_selections;
 3167            });
 3168
 3169            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3170                && let Some(workspace_id) =
 3171                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3172            {
 3173                let snapshot = self.buffer().read(cx).snapshot(cx);
 3174                let selections = selections.clone();
 3175                let background_executor = cx.background_executor().clone();
 3176                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3177                self.serialize_selections = cx.background_spawn(async move {
 3178                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3179                            let db_selections = selections
 3180                                .iter()
 3181                                .map(|selection| {
 3182                                    (
 3183                                        selection.start.to_offset(&snapshot),
 3184                                        selection.end.to_offset(&snapshot),
 3185                                    )
 3186                                })
 3187                                .collect();
 3188
 3189                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3190                                .await
 3191                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3192                                .log_err();
 3193                        });
 3194            }
 3195        }
 3196
 3197        cx.notify();
 3198    }
 3199
 3200    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3201        use text::ToOffset as _;
 3202        use text::ToPoint as _;
 3203
 3204        if self.mode.is_minimap()
 3205            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3206        {
 3207            return;
 3208        }
 3209
 3210        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3211            return;
 3212        };
 3213
 3214        let snapshot = singleton.read(cx).snapshot();
 3215        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3216            let display_snapshot = display_map.snapshot(cx);
 3217
 3218            display_snapshot
 3219                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3220                .map(|fold| {
 3221                    fold.range.start.text_anchor.to_point(&snapshot)
 3222                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3223                })
 3224                .collect()
 3225        });
 3226        self.update_restoration_data(cx, |data| {
 3227            data.folds = inmemory_folds;
 3228        });
 3229
 3230        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3231            return;
 3232        };
 3233        let background_executor = cx.background_executor().clone();
 3234        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3235        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3236            display_map
 3237                .snapshot(cx)
 3238                .folds_in_range(0..snapshot.len())
 3239                .map(|fold| {
 3240                    (
 3241                        fold.range.start.text_anchor.to_offset(&snapshot),
 3242                        fold.range.end.text_anchor.to_offset(&snapshot),
 3243                    )
 3244                })
 3245                .collect()
 3246        });
 3247        self.serialize_folds = cx.background_spawn(async move {
 3248            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3249            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3250                .await
 3251                .with_context(|| {
 3252                    format!(
 3253                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3254                    )
 3255                })
 3256                .log_err();
 3257        });
 3258    }
 3259
 3260    pub fn sync_selections(
 3261        &mut self,
 3262        other: Entity<Editor>,
 3263        cx: &mut Context<Self>,
 3264    ) -> gpui::Subscription {
 3265        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3266        self.selections.change_with(cx, |selections| {
 3267            selections.select_anchors(other_selections);
 3268        });
 3269
 3270        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3271            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3272                let other_selections = other.read(cx).selections.disjoint.to_vec();
 3273                if other_selections.is_empty() {
 3274                    return;
 3275                }
 3276                this.selections.change_with(cx, |selections| {
 3277                    selections.select_anchors(other_selections);
 3278                });
 3279            }
 3280        });
 3281
 3282        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3283            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3284                let these_selections = this.selections.disjoint.to_vec();
 3285                if these_selections.is_empty() {
 3286                    return;
 3287                }
 3288                other.update(cx, |other_editor, cx| {
 3289                    other_editor.selections.change_with(cx, |selections| {
 3290                        selections.select_anchors(these_selections);
 3291                    })
 3292                });
 3293            }
 3294        });
 3295
 3296        Subscription::join(other_subscription, this_subscription)
 3297    }
 3298
 3299    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3300    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3301    /// effects of selection change occur at the end of the transaction.
 3302    pub fn change_selections<R>(
 3303        &mut self,
 3304        effects: SelectionEffects,
 3305        window: &mut Window,
 3306        cx: &mut Context<Self>,
 3307        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3308    ) -> R {
 3309        if let Some(state) = &mut self.deferred_selection_effects_state {
 3310            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3311            state.effects.completions = effects.completions;
 3312            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3313            let (changed, result) = self.selections.change_with(cx, change);
 3314            state.changed |= changed;
 3315            return result;
 3316        }
 3317        let mut state = DeferredSelectionEffectsState {
 3318            changed: false,
 3319            effects,
 3320            old_cursor_position: self.selections.newest_anchor().head(),
 3321            history_entry: SelectionHistoryEntry {
 3322                selections: self.selections.disjoint_anchors(),
 3323                select_next_state: self.select_next_state.clone(),
 3324                select_prev_state: self.select_prev_state.clone(),
 3325                add_selections_state: self.add_selections_state.clone(),
 3326            },
 3327        };
 3328        let (changed, result) = self.selections.change_with(cx, change);
 3329        state.changed = state.changed || changed;
 3330        if self.defer_selection_effects {
 3331            self.deferred_selection_effects_state = Some(state);
 3332        } else {
 3333            self.apply_selection_effects(state, window, cx);
 3334        }
 3335        result
 3336    }
 3337
 3338    /// Defers the effects of selection change, so that the effects of multiple calls to
 3339    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3340    /// to selection history and the state of popovers based on selection position aren't
 3341    /// erroneously updated.
 3342    pub fn with_selection_effects_deferred<R>(
 3343        &mut self,
 3344        window: &mut Window,
 3345        cx: &mut Context<Self>,
 3346        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3347    ) -> R {
 3348        let already_deferred = self.defer_selection_effects;
 3349        self.defer_selection_effects = true;
 3350        let result = update(self, window, cx);
 3351        if !already_deferred {
 3352            self.defer_selection_effects = false;
 3353            if let Some(state) = self.deferred_selection_effects_state.take() {
 3354                self.apply_selection_effects(state, window, cx);
 3355            }
 3356        }
 3357        result
 3358    }
 3359
 3360    fn apply_selection_effects(
 3361        &mut self,
 3362        state: DeferredSelectionEffectsState,
 3363        window: &mut Window,
 3364        cx: &mut Context<Self>,
 3365    ) {
 3366        if state.changed {
 3367            self.selection_history.push(state.history_entry);
 3368
 3369            if let Some(autoscroll) = state.effects.scroll {
 3370                self.request_autoscroll(autoscroll, cx);
 3371            }
 3372
 3373            let old_cursor_position = &state.old_cursor_position;
 3374
 3375            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3376
 3377            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3378                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3379            }
 3380        }
 3381    }
 3382
 3383    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3384    where
 3385        I: IntoIterator<Item = (Range<S>, T)>,
 3386        S: ToOffset,
 3387        T: Into<Arc<str>>,
 3388    {
 3389        if self.read_only(cx) {
 3390            return;
 3391        }
 3392
 3393        self.buffer
 3394            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3395    }
 3396
 3397    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3398    where
 3399        I: IntoIterator<Item = (Range<S>, T)>,
 3400        S: ToOffset,
 3401        T: Into<Arc<str>>,
 3402    {
 3403        if self.read_only(cx) {
 3404            return;
 3405        }
 3406
 3407        self.buffer.update(cx, |buffer, cx| {
 3408            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3409        });
 3410    }
 3411
 3412    pub fn edit_with_block_indent<I, S, T>(
 3413        &mut self,
 3414        edits: I,
 3415        original_indent_columns: Vec<Option<u32>>,
 3416        cx: &mut Context<Self>,
 3417    ) where
 3418        I: IntoIterator<Item = (Range<S>, T)>,
 3419        S: ToOffset,
 3420        T: Into<Arc<str>>,
 3421    {
 3422        if self.read_only(cx) {
 3423            return;
 3424        }
 3425
 3426        self.buffer.update(cx, |buffer, cx| {
 3427            buffer.edit(
 3428                edits,
 3429                Some(AutoindentMode::Block {
 3430                    original_indent_columns,
 3431                }),
 3432                cx,
 3433            )
 3434        });
 3435    }
 3436
 3437    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3438        self.hide_context_menu(window, cx);
 3439
 3440        match phase {
 3441            SelectPhase::Begin {
 3442                position,
 3443                add,
 3444                click_count,
 3445            } => self.begin_selection(position, add, click_count, window, cx),
 3446            SelectPhase::BeginColumnar {
 3447                position,
 3448                goal_column,
 3449                reset,
 3450                mode,
 3451            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3452            SelectPhase::Extend {
 3453                position,
 3454                click_count,
 3455            } => self.extend_selection(position, click_count, window, cx),
 3456            SelectPhase::Update {
 3457                position,
 3458                goal_column,
 3459                scroll_delta,
 3460            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3461            SelectPhase::End => self.end_selection(window, cx),
 3462        }
 3463    }
 3464
 3465    fn extend_selection(
 3466        &mut self,
 3467        position: DisplayPoint,
 3468        click_count: usize,
 3469        window: &mut Window,
 3470        cx: &mut Context<Self>,
 3471    ) {
 3472        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3473        let tail = self.selections.newest::<usize>(cx).tail();
 3474        self.begin_selection(position, false, click_count, window, cx);
 3475
 3476        let position = position.to_offset(&display_map, Bias::Left);
 3477        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3478
 3479        let mut pending_selection = self
 3480            .selections
 3481            .pending_anchor()
 3482            .expect("extend_selection not called with pending selection");
 3483        if position >= tail {
 3484            pending_selection.start = tail_anchor;
 3485        } else {
 3486            pending_selection.end = tail_anchor;
 3487            pending_selection.reversed = true;
 3488        }
 3489
 3490        let mut pending_mode = self.selections.pending_mode().unwrap();
 3491        match &mut pending_mode {
 3492            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3493            _ => {}
 3494        }
 3495
 3496        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3497            SelectionEffects::scroll(Autoscroll::fit())
 3498        } else {
 3499            SelectionEffects::no_scroll()
 3500        };
 3501
 3502        self.change_selections(effects, window, cx, |s| {
 3503            s.set_pending(pending_selection, pending_mode)
 3504        });
 3505    }
 3506
 3507    fn begin_selection(
 3508        &mut self,
 3509        position: DisplayPoint,
 3510        add: bool,
 3511        click_count: usize,
 3512        window: &mut Window,
 3513        cx: &mut Context<Self>,
 3514    ) {
 3515        if !self.focus_handle.is_focused(window) {
 3516            self.last_focused_descendant = None;
 3517            window.focus(&self.focus_handle);
 3518        }
 3519
 3520        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3521        let buffer = &display_map.buffer_snapshot;
 3522        let position = display_map.clip_point(position, Bias::Left);
 3523
 3524        let start;
 3525        let end;
 3526        let mode;
 3527        let mut auto_scroll;
 3528        match click_count {
 3529            1 => {
 3530                start = buffer.anchor_before(position.to_point(&display_map));
 3531                end = start;
 3532                mode = SelectMode::Character;
 3533                auto_scroll = true;
 3534            }
 3535            2 => {
 3536                let position = display_map
 3537                    .clip_point(position, Bias::Left)
 3538                    .to_offset(&display_map, Bias::Left);
 3539                let (range, _) = buffer.surrounding_word(position, false);
 3540                start = buffer.anchor_before(range.start);
 3541                end = buffer.anchor_before(range.end);
 3542                mode = SelectMode::Word(start..end);
 3543                auto_scroll = true;
 3544            }
 3545            3 => {
 3546                let position = display_map
 3547                    .clip_point(position, Bias::Left)
 3548                    .to_point(&display_map);
 3549                let line_start = display_map.prev_line_boundary(position).0;
 3550                let next_line_start = buffer.clip_point(
 3551                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3552                    Bias::Left,
 3553                );
 3554                start = buffer.anchor_before(line_start);
 3555                end = buffer.anchor_before(next_line_start);
 3556                mode = SelectMode::Line(start..end);
 3557                auto_scroll = true;
 3558            }
 3559            _ => {
 3560                start = buffer.anchor_before(0);
 3561                end = buffer.anchor_before(buffer.len());
 3562                mode = SelectMode::All;
 3563                auto_scroll = false;
 3564            }
 3565        }
 3566        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3567
 3568        let point_to_delete: Option<usize> = {
 3569            let selected_points: Vec<Selection<Point>> =
 3570                self.selections.disjoint_in_range(start..end, cx);
 3571
 3572            if !add || click_count > 1 {
 3573                None
 3574            } else if !selected_points.is_empty() {
 3575                Some(selected_points[0].id)
 3576            } else {
 3577                let clicked_point_already_selected =
 3578                    self.selections.disjoint.iter().find(|selection| {
 3579                        selection.start.to_point(buffer) == start.to_point(buffer)
 3580                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3581                    });
 3582
 3583                clicked_point_already_selected.map(|selection| selection.id)
 3584            }
 3585        };
 3586
 3587        let selections_count = self.selections.count();
 3588        let effects = if auto_scroll {
 3589            SelectionEffects::default()
 3590        } else {
 3591            SelectionEffects::no_scroll()
 3592        };
 3593
 3594        self.change_selections(effects, window, cx, |s| {
 3595            if let Some(point_to_delete) = point_to_delete {
 3596                s.delete(point_to_delete);
 3597
 3598                if selections_count == 1 {
 3599                    s.set_pending_anchor_range(start..end, mode);
 3600                }
 3601            } else {
 3602                if !add {
 3603                    s.clear_disjoint();
 3604                }
 3605
 3606                s.set_pending_anchor_range(start..end, mode);
 3607            }
 3608        });
 3609    }
 3610
 3611    fn begin_columnar_selection(
 3612        &mut self,
 3613        position: DisplayPoint,
 3614        goal_column: u32,
 3615        reset: bool,
 3616        mode: ColumnarMode,
 3617        window: &mut Window,
 3618        cx: &mut Context<Self>,
 3619    ) {
 3620        if !self.focus_handle.is_focused(window) {
 3621            self.last_focused_descendant = None;
 3622            window.focus(&self.focus_handle);
 3623        }
 3624
 3625        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3626
 3627        if reset {
 3628            let pointer_position = display_map
 3629                .buffer_snapshot
 3630                .anchor_before(position.to_point(&display_map));
 3631
 3632            self.change_selections(
 3633                SelectionEffects::scroll(Autoscroll::newest()),
 3634                window,
 3635                cx,
 3636                |s| {
 3637                    s.clear_disjoint();
 3638                    s.set_pending_anchor_range(
 3639                        pointer_position..pointer_position,
 3640                        SelectMode::Character,
 3641                    );
 3642                },
 3643            );
 3644        };
 3645
 3646        let tail = self.selections.newest::<Point>(cx).tail();
 3647        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3648        self.columnar_selection_state = match mode {
 3649            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3650                selection_tail: selection_anchor,
 3651                display_point: if reset {
 3652                    if position.column() != goal_column {
 3653                        Some(DisplayPoint::new(position.row(), goal_column))
 3654                    } else {
 3655                        None
 3656                    }
 3657                } else {
 3658                    None
 3659                },
 3660            }),
 3661            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3662                selection_tail: selection_anchor,
 3663            }),
 3664        };
 3665
 3666        if !reset {
 3667            self.select_columns(position, goal_column, &display_map, window, cx);
 3668        }
 3669    }
 3670
 3671    fn update_selection(
 3672        &mut self,
 3673        position: DisplayPoint,
 3674        goal_column: u32,
 3675        scroll_delta: gpui::Point<f32>,
 3676        window: &mut Window,
 3677        cx: &mut Context<Self>,
 3678    ) {
 3679        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3680
 3681        if self.columnar_selection_state.is_some() {
 3682            self.select_columns(position, goal_column, &display_map, window, cx);
 3683        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3684            let buffer = &display_map.buffer_snapshot;
 3685            let head;
 3686            let tail;
 3687            let mode = self.selections.pending_mode().unwrap();
 3688            match &mode {
 3689                SelectMode::Character => {
 3690                    head = position.to_point(&display_map);
 3691                    tail = pending.tail().to_point(buffer);
 3692                }
 3693                SelectMode::Word(original_range) => {
 3694                    let offset = display_map
 3695                        .clip_point(position, Bias::Left)
 3696                        .to_offset(&display_map, Bias::Left);
 3697                    let original_range = original_range.to_offset(buffer);
 3698
 3699                    let head_offset = if buffer.is_inside_word(offset, false)
 3700                        || original_range.contains(&offset)
 3701                    {
 3702                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3703                        if word_range.start < original_range.start {
 3704                            word_range.start
 3705                        } else {
 3706                            word_range.end
 3707                        }
 3708                    } else {
 3709                        offset
 3710                    };
 3711
 3712                    head = head_offset.to_point(buffer);
 3713                    if head_offset <= original_range.start {
 3714                        tail = original_range.end.to_point(buffer);
 3715                    } else {
 3716                        tail = original_range.start.to_point(buffer);
 3717                    }
 3718                }
 3719                SelectMode::Line(original_range) => {
 3720                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3721
 3722                    let position = display_map
 3723                        .clip_point(position, Bias::Left)
 3724                        .to_point(&display_map);
 3725                    let line_start = display_map.prev_line_boundary(position).0;
 3726                    let next_line_start = buffer.clip_point(
 3727                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3728                        Bias::Left,
 3729                    );
 3730
 3731                    if line_start < original_range.start {
 3732                        head = line_start
 3733                    } else {
 3734                        head = next_line_start
 3735                    }
 3736
 3737                    if head <= original_range.start {
 3738                        tail = original_range.end;
 3739                    } else {
 3740                        tail = original_range.start;
 3741                    }
 3742                }
 3743                SelectMode::All => {
 3744                    return;
 3745                }
 3746            };
 3747
 3748            if head < tail {
 3749                pending.start = buffer.anchor_before(head);
 3750                pending.end = buffer.anchor_before(tail);
 3751                pending.reversed = true;
 3752            } else {
 3753                pending.start = buffer.anchor_before(tail);
 3754                pending.end = buffer.anchor_before(head);
 3755                pending.reversed = false;
 3756            }
 3757
 3758            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3759                s.set_pending(pending, mode);
 3760            });
 3761        } else {
 3762            log::error!("update_selection dispatched with no pending selection");
 3763            return;
 3764        }
 3765
 3766        self.apply_scroll_delta(scroll_delta, window, cx);
 3767        cx.notify();
 3768    }
 3769
 3770    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3771        self.columnar_selection_state.take();
 3772        if self.selections.pending_anchor().is_some() {
 3773            let selections = self.selections.all::<usize>(cx);
 3774            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3775                s.select(selections);
 3776                s.clear_pending();
 3777            });
 3778        }
 3779    }
 3780
 3781    fn select_columns(
 3782        &mut self,
 3783        head: DisplayPoint,
 3784        goal_column: u32,
 3785        display_map: &DisplaySnapshot,
 3786        window: &mut Window,
 3787        cx: &mut Context<Self>,
 3788    ) {
 3789        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3790            return;
 3791        };
 3792
 3793        let tail = match columnar_state {
 3794            ColumnarSelectionState::FromMouse {
 3795                selection_tail,
 3796                display_point,
 3797            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3798            ColumnarSelectionState::FromSelection { selection_tail } => {
 3799                selection_tail.to_display_point(display_map)
 3800            }
 3801        };
 3802
 3803        let start_row = cmp::min(tail.row(), head.row());
 3804        let end_row = cmp::max(tail.row(), head.row());
 3805        let start_column = cmp::min(tail.column(), goal_column);
 3806        let end_column = cmp::max(tail.column(), goal_column);
 3807        let reversed = start_column < tail.column();
 3808
 3809        let selection_ranges = (start_row.0..=end_row.0)
 3810            .map(DisplayRow)
 3811            .filter_map(|row| {
 3812                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3813                    || start_column <= display_map.line_len(row))
 3814                    && !display_map.is_block_line(row)
 3815                {
 3816                    let start = display_map
 3817                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3818                        .to_point(display_map);
 3819                    let end = display_map
 3820                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3821                        .to_point(display_map);
 3822                    if reversed {
 3823                        Some(end..start)
 3824                    } else {
 3825                        Some(start..end)
 3826                    }
 3827                } else {
 3828                    None
 3829                }
 3830            })
 3831            .collect::<Vec<_>>();
 3832
 3833        let ranges = match columnar_state {
 3834            ColumnarSelectionState::FromMouse { .. } => {
 3835                let mut non_empty_ranges = selection_ranges
 3836                    .iter()
 3837                    .filter(|selection_range| selection_range.start != selection_range.end)
 3838                    .peekable();
 3839                if non_empty_ranges.peek().is_some() {
 3840                    non_empty_ranges.cloned().collect()
 3841                } else {
 3842                    selection_ranges
 3843                }
 3844            }
 3845            _ => selection_ranges,
 3846        };
 3847
 3848        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3849            s.select_ranges(ranges);
 3850        });
 3851        cx.notify();
 3852    }
 3853
 3854    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3855        self.selections
 3856            .all_adjusted(cx)
 3857            .iter()
 3858            .any(|selection| !selection.is_empty())
 3859    }
 3860
 3861    pub fn has_pending_nonempty_selection(&self) -> bool {
 3862        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3863            Some(Selection { start, end, .. }) => start != end,
 3864            None => false,
 3865        };
 3866
 3867        pending_nonempty_selection
 3868            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3869    }
 3870
 3871    pub fn has_pending_selection(&self) -> bool {
 3872        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3873    }
 3874
 3875    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3876        self.selection_mark_mode = false;
 3877        self.selection_drag_state = SelectionDragState::None;
 3878
 3879        if self.clear_expanded_diff_hunks(cx) {
 3880            cx.notify();
 3881            return;
 3882        }
 3883        if self.dismiss_menus_and_popups(true, window, cx) {
 3884            return;
 3885        }
 3886
 3887        if self.mode.is_full()
 3888            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3889        {
 3890            return;
 3891        }
 3892
 3893        cx.propagate();
 3894    }
 3895
 3896    pub fn dismiss_menus_and_popups(
 3897        &mut self,
 3898        is_user_requested: bool,
 3899        window: &mut Window,
 3900        cx: &mut Context<Self>,
 3901    ) -> bool {
 3902        if self.take_rename(false, window, cx).is_some() {
 3903            return true;
 3904        }
 3905
 3906        if hide_hover(self, cx) {
 3907            return true;
 3908        }
 3909
 3910        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3911            return true;
 3912        }
 3913
 3914        if self.hide_context_menu(window, cx).is_some() {
 3915            return true;
 3916        }
 3917
 3918        if self.mouse_context_menu.take().is_some() {
 3919            return true;
 3920        }
 3921
 3922        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3923            return true;
 3924        }
 3925
 3926        if self.snippet_stack.pop().is_some() {
 3927            return true;
 3928        }
 3929
 3930        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3931            self.dismiss_diagnostics(cx);
 3932            return true;
 3933        }
 3934
 3935        false
 3936    }
 3937
 3938    fn linked_editing_ranges_for(
 3939        &self,
 3940        selection: Range<text::Anchor>,
 3941        cx: &App,
 3942    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3943        if self.linked_edit_ranges.is_empty() {
 3944            return None;
 3945        }
 3946        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3947            selection.end.buffer_id.and_then(|end_buffer_id| {
 3948                if selection.start.buffer_id != Some(end_buffer_id) {
 3949                    return None;
 3950                }
 3951                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3952                let snapshot = buffer.read(cx).snapshot();
 3953                self.linked_edit_ranges
 3954                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3955                    .map(|ranges| (ranges, snapshot, buffer))
 3956            })?;
 3957        use text::ToOffset as TO;
 3958        // find offset from the start of current range to current cursor position
 3959        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3960
 3961        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3962        let start_difference = start_offset - start_byte_offset;
 3963        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3964        let end_difference = end_offset - start_byte_offset;
 3965        // Current range has associated linked ranges.
 3966        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3967        for range in linked_ranges.iter() {
 3968            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3969            let end_offset = start_offset + end_difference;
 3970            let start_offset = start_offset + start_difference;
 3971            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3972                continue;
 3973            }
 3974            if self.selections.disjoint_anchor_ranges().any(|s| {
 3975                if s.start.buffer_id != selection.start.buffer_id
 3976                    || s.end.buffer_id != selection.end.buffer_id
 3977                {
 3978                    return false;
 3979                }
 3980                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3981                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3982            }) {
 3983                continue;
 3984            }
 3985            let start = buffer_snapshot.anchor_after(start_offset);
 3986            let end = buffer_snapshot.anchor_after(end_offset);
 3987            linked_edits
 3988                .entry(buffer.clone())
 3989                .or_default()
 3990                .push(start..end);
 3991        }
 3992        Some(linked_edits)
 3993    }
 3994
 3995    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3996        let text: Arc<str> = text.into();
 3997
 3998        if self.read_only(cx) {
 3999            return;
 4000        }
 4001
 4002        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4003
 4004        let selections = self.selections.all_adjusted(cx);
 4005        let mut bracket_inserted = false;
 4006        let mut edits = Vec::new();
 4007        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4008        let mut new_selections = Vec::with_capacity(selections.len());
 4009        let mut new_autoclose_regions = Vec::new();
 4010        let snapshot = self.buffer.read(cx).read(cx);
 4011        let mut clear_linked_edit_ranges = false;
 4012
 4013        for (selection, autoclose_region) in
 4014            self.selections_with_autoclose_regions(selections, &snapshot)
 4015        {
 4016            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4017                // Determine if the inserted text matches the opening or closing
 4018                // bracket of any of this language's bracket pairs.
 4019                let mut bracket_pair = None;
 4020                let mut is_bracket_pair_start = false;
 4021                let mut is_bracket_pair_end = false;
 4022                if !text.is_empty() {
 4023                    let mut bracket_pair_matching_end = None;
 4024                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4025                    //  and they are removing the character that triggered IME popup.
 4026                    for (pair, enabled) in scope.brackets() {
 4027                        if !pair.close && !pair.surround {
 4028                            continue;
 4029                        }
 4030
 4031                        if enabled && pair.start.ends_with(text.as_ref()) {
 4032                            let prefix_len = pair.start.len() - text.len();
 4033                            let preceding_text_matches_prefix = prefix_len == 0
 4034                                || (selection.start.column >= (prefix_len as u32)
 4035                                    && snapshot.contains_str_at(
 4036                                        Point::new(
 4037                                            selection.start.row,
 4038                                            selection.start.column - (prefix_len as u32),
 4039                                        ),
 4040                                        &pair.start[..prefix_len],
 4041                                    ));
 4042                            if preceding_text_matches_prefix {
 4043                                bracket_pair = Some(pair.clone());
 4044                                is_bracket_pair_start = true;
 4045                                break;
 4046                            }
 4047                        }
 4048                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4049                        {
 4050                            // take first bracket pair matching end, but don't break in case a later bracket
 4051                            // pair matches start
 4052                            bracket_pair_matching_end = Some(pair.clone());
 4053                        }
 4054                    }
 4055                    if let Some(end) = bracket_pair_matching_end
 4056                        && bracket_pair.is_none()
 4057                    {
 4058                        bracket_pair = Some(end);
 4059                        is_bracket_pair_end = true;
 4060                    }
 4061                }
 4062
 4063                if let Some(bracket_pair) = bracket_pair {
 4064                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4065                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4066                    let auto_surround =
 4067                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4068                    if selection.is_empty() {
 4069                        if is_bracket_pair_start {
 4070                            // If the inserted text is a suffix of an opening bracket and the
 4071                            // selection is preceded by the rest of the opening bracket, then
 4072                            // insert the closing bracket.
 4073                            let following_text_allows_autoclose = snapshot
 4074                                .chars_at(selection.start)
 4075                                .next()
 4076                                .is_none_or(|c| scope.should_autoclose_before(c));
 4077
 4078                            let preceding_text_allows_autoclose = selection.start.column == 0
 4079                                || snapshot
 4080                                    .reversed_chars_at(selection.start)
 4081                                    .next()
 4082                                    .is_none_or(|c| {
 4083                                        bracket_pair.start != bracket_pair.end
 4084                                            || !snapshot
 4085                                                .char_classifier_at(selection.start)
 4086                                                .is_word(c)
 4087                                    });
 4088
 4089                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4090                                && bracket_pair.start.len() == 1
 4091                            {
 4092                                let target = bracket_pair.start.chars().next().unwrap();
 4093                                let current_line_count = snapshot
 4094                                    .reversed_chars_at(selection.start)
 4095                                    .take_while(|&c| c != '\n')
 4096                                    .filter(|&c| c == target)
 4097                                    .count();
 4098                                current_line_count % 2 == 1
 4099                            } else {
 4100                                false
 4101                            };
 4102
 4103                            if autoclose
 4104                                && bracket_pair.close
 4105                                && following_text_allows_autoclose
 4106                                && preceding_text_allows_autoclose
 4107                                && !is_closing_quote
 4108                            {
 4109                                let anchor = snapshot.anchor_before(selection.end);
 4110                                new_selections.push((selection.map(|_| anchor), text.len()));
 4111                                new_autoclose_regions.push((
 4112                                    anchor,
 4113                                    text.len(),
 4114                                    selection.id,
 4115                                    bracket_pair.clone(),
 4116                                ));
 4117                                edits.push((
 4118                                    selection.range(),
 4119                                    format!("{}{}", text, bracket_pair.end).into(),
 4120                                ));
 4121                                bracket_inserted = true;
 4122                                continue;
 4123                            }
 4124                        }
 4125
 4126                        if let Some(region) = autoclose_region {
 4127                            // If the selection is followed by an auto-inserted closing bracket,
 4128                            // then don't insert that closing bracket again; just move the selection
 4129                            // past the closing bracket.
 4130                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4131                                && text.as_ref() == region.pair.end.as_str()
 4132                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4133                            if should_skip {
 4134                                let anchor = snapshot.anchor_after(selection.end);
 4135                                new_selections
 4136                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4137                                continue;
 4138                            }
 4139                        }
 4140
 4141                        let always_treat_brackets_as_autoclosed = snapshot
 4142                            .language_settings_at(selection.start, cx)
 4143                            .always_treat_brackets_as_autoclosed;
 4144                        if always_treat_brackets_as_autoclosed
 4145                            && is_bracket_pair_end
 4146                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4147                        {
 4148                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4149                            // and the inserted text is a closing bracket and the selection is followed
 4150                            // by the closing bracket then move the selection past the closing bracket.
 4151                            let anchor = snapshot.anchor_after(selection.end);
 4152                            new_selections.push((selection.map(|_| anchor), text.len()));
 4153                            continue;
 4154                        }
 4155                    }
 4156                    // If an opening bracket is 1 character long and is typed while
 4157                    // text is selected, then surround that text with the bracket pair.
 4158                    else if auto_surround
 4159                        && bracket_pair.surround
 4160                        && is_bracket_pair_start
 4161                        && bracket_pair.start.chars().count() == 1
 4162                    {
 4163                        edits.push((selection.start..selection.start, text.clone()));
 4164                        edits.push((
 4165                            selection.end..selection.end,
 4166                            bracket_pair.end.as_str().into(),
 4167                        ));
 4168                        bracket_inserted = true;
 4169                        new_selections.push((
 4170                            Selection {
 4171                                id: selection.id,
 4172                                start: snapshot.anchor_after(selection.start),
 4173                                end: snapshot.anchor_before(selection.end),
 4174                                reversed: selection.reversed,
 4175                                goal: selection.goal,
 4176                            },
 4177                            0,
 4178                        ));
 4179                        continue;
 4180                    }
 4181                }
 4182            }
 4183
 4184            if self.auto_replace_emoji_shortcode
 4185                && selection.is_empty()
 4186                && text.as_ref().ends_with(':')
 4187                && let Some(possible_emoji_short_code) =
 4188                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4189                && !possible_emoji_short_code.is_empty()
 4190                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4191            {
 4192                let emoji_shortcode_start = Point::new(
 4193                    selection.start.row,
 4194                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4195                );
 4196
 4197                // Remove shortcode from buffer
 4198                edits.push((
 4199                    emoji_shortcode_start..selection.start,
 4200                    "".to_string().into(),
 4201                ));
 4202                new_selections.push((
 4203                    Selection {
 4204                        id: selection.id,
 4205                        start: snapshot.anchor_after(emoji_shortcode_start),
 4206                        end: snapshot.anchor_before(selection.start),
 4207                        reversed: selection.reversed,
 4208                        goal: selection.goal,
 4209                    },
 4210                    0,
 4211                ));
 4212
 4213                // Insert emoji
 4214                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4215                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4216                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4217
 4218                continue;
 4219            }
 4220
 4221            // If not handling any auto-close operation, then just replace the selected
 4222            // text with the given input and move the selection to the end of the
 4223            // newly inserted text.
 4224            let anchor = snapshot.anchor_after(selection.end);
 4225            if !self.linked_edit_ranges.is_empty() {
 4226                let start_anchor = snapshot.anchor_before(selection.start);
 4227
 4228                let is_word_char = text.chars().next().is_none_or(|char| {
 4229                    let classifier = snapshot
 4230                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4231                        .ignore_punctuation(true);
 4232                    classifier.is_word(char)
 4233                });
 4234
 4235                if is_word_char {
 4236                    if let Some(ranges) = self
 4237                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4238                    {
 4239                        for (buffer, edits) in ranges {
 4240                            linked_edits
 4241                                .entry(buffer.clone())
 4242                                .or_default()
 4243                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4244                        }
 4245                    }
 4246                } else {
 4247                    clear_linked_edit_ranges = true;
 4248                }
 4249            }
 4250
 4251            new_selections.push((selection.map(|_| anchor), 0));
 4252            edits.push((selection.start..selection.end, text.clone()));
 4253        }
 4254
 4255        drop(snapshot);
 4256
 4257        self.transact(window, cx, |this, window, cx| {
 4258            if clear_linked_edit_ranges {
 4259                this.linked_edit_ranges.clear();
 4260            }
 4261            let initial_buffer_versions =
 4262                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4263
 4264            this.buffer.update(cx, |buffer, cx| {
 4265                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4266            });
 4267            for (buffer, edits) in linked_edits {
 4268                buffer.update(cx, |buffer, cx| {
 4269                    let snapshot = buffer.snapshot();
 4270                    let edits = edits
 4271                        .into_iter()
 4272                        .map(|(range, text)| {
 4273                            use text::ToPoint as TP;
 4274                            let end_point = TP::to_point(&range.end, &snapshot);
 4275                            let start_point = TP::to_point(&range.start, &snapshot);
 4276                            (start_point..end_point, text)
 4277                        })
 4278                        .sorted_by_key(|(range, _)| range.start);
 4279                    buffer.edit(edits, None, cx);
 4280                })
 4281            }
 4282            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4283            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4284            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4285            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4286                .zip(new_selection_deltas)
 4287                .map(|(selection, delta)| Selection {
 4288                    id: selection.id,
 4289                    start: selection.start + delta,
 4290                    end: selection.end + delta,
 4291                    reversed: selection.reversed,
 4292                    goal: SelectionGoal::None,
 4293                })
 4294                .collect::<Vec<_>>();
 4295
 4296            let mut i = 0;
 4297            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4298                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4299                let start = map.buffer_snapshot.anchor_before(position);
 4300                let end = map.buffer_snapshot.anchor_after(position);
 4301                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4302                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4303                        Ordering::Less => i += 1,
 4304                        Ordering::Greater => break,
 4305                        Ordering::Equal => {
 4306                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4307                                Ordering::Less => i += 1,
 4308                                Ordering::Equal => break,
 4309                                Ordering::Greater => break,
 4310                            }
 4311                        }
 4312                    }
 4313                }
 4314                this.autoclose_regions.insert(
 4315                    i,
 4316                    AutocloseRegion {
 4317                        selection_id,
 4318                        range: start..end,
 4319                        pair,
 4320                    },
 4321                );
 4322            }
 4323
 4324            let had_active_edit_prediction = this.has_active_edit_prediction();
 4325            this.change_selections(
 4326                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4327                window,
 4328                cx,
 4329                |s| s.select(new_selections),
 4330            );
 4331
 4332            if !bracket_inserted
 4333                && let Some(on_type_format_task) =
 4334                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4335            {
 4336                on_type_format_task.detach_and_log_err(cx);
 4337            }
 4338
 4339            let editor_settings = EditorSettings::get_global(cx);
 4340            if bracket_inserted
 4341                && (editor_settings.auto_signature_help
 4342                    || editor_settings.show_signature_help_after_edits)
 4343            {
 4344                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4345            }
 4346
 4347            let trigger_in_words =
 4348                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4349            if this.hard_wrap.is_some() {
 4350                let latest: Range<Point> = this.selections.newest(cx).range();
 4351                if latest.is_empty()
 4352                    && this
 4353                        .buffer()
 4354                        .read(cx)
 4355                        .snapshot(cx)
 4356                        .line_len(MultiBufferRow(latest.start.row))
 4357                        == latest.start.column
 4358                {
 4359                    this.rewrap_impl(
 4360                        RewrapOptions {
 4361                            override_language_settings: true,
 4362                            preserve_existing_whitespace: true,
 4363                        },
 4364                        cx,
 4365                    )
 4366                }
 4367            }
 4368            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4369            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4370            this.refresh_edit_prediction(true, false, window, cx);
 4371            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4372        });
 4373    }
 4374
 4375    fn find_possible_emoji_shortcode_at_position(
 4376        snapshot: &MultiBufferSnapshot,
 4377        position: Point,
 4378    ) -> Option<String> {
 4379        let mut chars = Vec::new();
 4380        let mut found_colon = false;
 4381        for char in snapshot.reversed_chars_at(position).take(100) {
 4382            // Found a possible emoji shortcode in the middle of the buffer
 4383            if found_colon {
 4384                if char.is_whitespace() {
 4385                    chars.reverse();
 4386                    return Some(chars.iter().collect());
 4387                }
 4388                // If the previous character is not a whitespace, we are in the middle of a word
 4389                // and we only want to complete the shortcode if the word is made up of other emojis
 4390                let mut containing_word = String::new();
 4391                for ch in snapshot
 4392                    .reversed_chars_at(position)
 4393                    .skip(chars.len() + 1)
 4394                    .take(100)
 4395                {
 4396                    if ch.is_whitespace() {
 4397                        break;
 4398                    }
 4399                    containing_word.push(ch);
 4400                }
 4401                let containing_word = containing_word.chars().rev().collect::<String>();
 4402                if util::word_consists_of_emojis(containing_word.as_str()) {
 4403                    chars.reverse();
 4404                    return Some(chars.iter().collect());
 4405                }
 4406            }
 4407
 4408            if char.is_whitespace() || !char.is_ascii() {
 4409                return None;
 4410            }
 4411            if char == ':' {
 4412                found_colon = true;
 4413            } else {
 4414                chars.push(char);
 4415            }
 4416        }
 4417        // Found a possible emoji shortcode at the beginning of the buffer
 4418        chars.reverse();
 4419        Some(chars.iter().collect())
 4420    }
 4421
 4422    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4423        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4424        self.transact(window, cx, |this, window, cx| {
 4425            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4426                let selections = this.selections.all::<usize>(cx);
 4427                let multi_buffer = this.buffer.read(cx);
 4428                let buffer = multi_buffer.snapshot(cx);
 4429                selections
 4430                    .iter()
 4431                    .map(|selection| {
 4432                        let start_point = selection.start.to_point(&buffer);
 4433                        let mut existing_indent =
 4434                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4435                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4436                        let start = selection.start;
 4437                        let end = selection.end;
 4438                        let selection_is_empty = start == end;
 4439                        let language_scope = buffer.language_scope_at(start);
 4440                        let (
 4441                            comment_delimiter,
 4442                            doc_delimiter,
 4443                            insert_extra_newline,
 4444                            indent_on_newline,
 4445                            indent_on_extra_newline,
 4446                        ) = if let Some(language) = &language_scope {
 4447                            let mut insert_extra_newline =
 4448                                insert_extra_newline_brackets(&buffer, start..end, language)
 4449                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4450
 4451                            // Comment extension on newline is allowed only for cursor selections
 4452                            let comment_delimiter = maybe!({
 4453                                if !selection_is_empty {
 4454                                    return None;
 4455                                }
 4456
 4457                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4458                                    return None;
 4459                                }
 4460
 4461                                let delimiters = language.line_comment_prefixes();
 4462                                let max_len_of_delimiter =
 4463                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4464                                let (snapshot, range) =
 4465                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4466
 4467                                let num_of_whitespaces = snapshot
 4468                                    .chars_for_range(range.clone())
 4469                                    .take_while(|c| c.is_whitespace())
 4470                                    .count();
 4471                                let comment_candidate = snapshot
 4472                                    .chars_for_range(range.clone())
 4473                                    .skip(num_of_whitespaces)
 4474                                    .take(max_len_of_delimiter)
 4475                                    .collect::<String>();
 4476                                let (delimiter, trimmed_len) = delimiters
 4477                                    .iter()
 4478                                    .filter_map(|delimiter| {
 4479                                        let prefix = delimiter.trim_end();
 4480                                        if comment_candidate.starts_with(prefix) {
 4481                                            Some((delimiter, prefix.len()))
 4482                                        } else {
 4483                                            None
 4484                                        }
 4485                                    })
 4486                                    .max_by_key(|(_, len)| *len)?;
 4487
 4488                                if let Some(BlockCommentConfig {
 4489                                    start: block_start, ..
 4490                                }) = language.block_comment()
 4491                                {
 4492                                    let block_start_trimmed = block_start.trim_end();
 4493                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4494                                        let line_content = snapshot
 4495                                            .chars_for_range(range)
 4496                                            .skip(num_of_whitespaces)
 4497                                            .take(block_start_trimmed.len())
 4498                                            .collect::<String>();
 4499
 4500                                        if line_content.starts_with(block_start_trimmed) {
 4501                                            return None;
 4502                                        }
 4503                                    }
 4504                                }
 4505
 4506                                let cursor_is_placed_after_comment_marker =
 4507                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4508                                if cursor_is_placed_after_comment_marker {
 4509                                    Some(delimiter.clone())
 4510                                } else {
 4511                                    None
 4512                                }
 4513                            });
 4514
 4515                            let mut indent_on_newline = IndentSize::spaces(0);
 4516                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4517
 4518                            let doc_delimiter = maybe!({
 4519                                if !selection_is_empty {
 4520                                    return None;
 4521                                }
 4522
 4523                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4524                                    return None;
 4525                                }
 4526
 4527                                let BlockCommentConfig {
 4528                                    start: start_tag,
 4529                                    end: end_tag,
 4530                                    prefix: delimiter,
 4531                                    tab_size: len,
 4532                                } = language.documentation_comment()?;
 4533                                let is_within_block_comment = buffer
 4534                                    .language_scope_at(start_point)
 4535                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4536                                if !is_within_block_comment {
 4537                                    return None;
 4538                                }
 4539
 4540                                let (snapshot, range) =
 4541                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4542
 4543                                let num_of_whitespaces = snapshot
 4544                                    .chars_for_range(range.clone())
 4545                                    .take_while(|c| c.is_whitespace())
 4546                                    .count();
 4547
 4548                                // 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.
 4549                                let column = start_point.column;
 4550                                let cursor_is_after_start_tag = {
 4551                                    let start_tag_len = start_tag.len();
 4552                                    let start_tag_line = snapshot
 4553                                        .chars_for_range(range.clone())
 4554                                        .skip(num_of_whitespaces)
 4555                                        .take(start_tag_len)
 4556                                        .collect::<String>();
 4557                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4558                                        num_of_whitespaces + start_tag_len <= column as usize
 4559                                    } else {
 4560                                        false
 4561                                    }
 4562                                };
 4563
 4564                                let cursor_is_after_delimiter = {
 4565                                    let delimiter_trim = delimiter.trim_end();
 4566                                    let delimiter_line = snapshot
 4567                                        .chars_for_range(range.clone())
 4568                                        .skip(num_of_whitespaces)
 4569                                        .take(delimiter_trim.len())
 4570                                        .collect::<String>();
 4571                                    if delimiter_line.starts_with(delimiter_trim) {
 4572                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4573                                    } else {
 4574                                        false
 4575                                    }
 4576                                };
 4577
 4578                                let cursor_is_before_end_tag_if_exists = {
 4579                                    let mut char_position = 0u32;
 4580                                    let mut end_tag_offset = None;
 4581
 4582                                    'outer: for chunk in snapshot.text_for_range(range) {
 4583                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4584                                            let chars_before_match =
 4585                                                chunk[..byte_pos].chars().count() as u32;
 4586                                            end_tag_offset =
 4587                                                Some(char_position + chars_before_match);
 4588                                            break 'outer;
 4589                                        }
 4590                                        char_position += chunk.chars().count() as u32;
 4591                                    }
 4592
 4593                                    if let Some(end_tag_offset) = end_tag_offset {
 4594                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4595                                        if cursor_is_after_start_tag {
 4596                                            if cursor_is_before_end_tag {
 4597                                                insert_extra_newline = true;
 4598                                            }
 4599                                            let cursor_is_at_start_of_end_tag =
 4600                                                column == end_tag_offset;
 4601                                            if cursor_is_at_start_of_end_tag {
 4602                                                indent_on_extra_newline.len = *len;
 4603                                            }
 4604                                        }
 4605                                        cursor_is_before_end_tag
 4606                                    } else {
 4607                                        true
 4608                                    }
 4609                                };
 4610
 4611                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4612                                    && cursor_is_before_end_tag_if_exists
 4613                                {
 4614                                    if cursor_is_after_start_tag {
 4615                                        indent_on_newline.len = *len;
 4616                                    }
 4617                                    Some(delimiter.clone())
 4618                                } else {
 4619                                    None
 4620                                }
 4621                            });
 4622
 4623                            (
 4624                                comment_delimiter,
 4625                                doc_delimiter,
 4626                                insert_extra_newline,
 4627                                indent_on_newline,
 4628                                indent_on_extra_newline,
 4629                            )
 4630                        } else {
 4631                            (
 4632                                None,
 4633                                None,
 4634                                false,
 4635                                IndentSize::default(),
 4636                                IndentSize::default(),
 4637                            )
 4638                        };
 4639
 4640                        let prevent_auto_indent = doc_delimiter.is_some();
 4641                        let delimiter = comment_delimiter.or(doc_delimiter);
 4642
 4643                        let capacity_for_delimiter =
 4644                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4645                        let mut new_text = String::with_capacity(
 4646                            1 + capacity_for_delimiter
 4647                                + existing_indent.len as usize
 4648                                + indent_on_newline.len as usize
 4649                                + indent_on_extra_newline.len as usize,
 4650                        );
 4651                        new_text.push('\n');
 4652                        new_text.extend(existing_indent.chars());
 4653                        new_text.extend(indent_on_newline.chars());
 4654
 4655                        if let Some(delimiter) = &delimiter {
 4656                            new_text.push_str(delimiter);
 4657                        }
 4658
 4659                        if insert_extra_newline {
 4660                            new_text.push('\n');
 4661                            new_text.extend(existing_indent.chars());
 4662                            new_text.extend(indent_on_extra_newline.chars());
 4663                        }
 4664
 4665                        let anchor = buffer.anchor_after(end);
 4666                        let new_selection = selection.map(|_| anchor);
 4667                        (
 4668                            ((start..end, new_text), prevent_auto_indent),
 4669                            (insert_extra_newline, new_selection),
 4670                        )
 4671                    })
 4672                    .unzip()
 4673            };
 4674
 4675            let mut auto_indent_edits = Vec::new();
 4676            let mut edits = Vec::new();
 4677            for (edit, prevent_auto_indent) in edits_with_flags {
 4678                if prevent_auto_indent {
 4679                    edits.push(edit);
 4680                } else {
 4681                    auto_indent_edits.push(edit);
 4682                }
 4683            }
 4684            if !edits.is_empty() {
 4685                this.edit(edits, cx);
 4686            }
 4687            if !auto_indent_edits.is_empty() {
 4688                this.edit_with_autoindent(auto_indent_edits, cx);
 4689            }
 4690
 4691            let buffer = this.buffer.read(cx).snapshot(cx);
 4692            let new_selections = selection_info
 4693                .into_iter()
 4694                .map(|(extra_newline_inserted, new_selection)| {
 4695                    let mut cursor = new_selection.end.to_point(&buffer);
 4696                    if extra_newline_inserted {
 4697                        cursor.row -= 1;
 4698                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4699                    }
 4700                    new_selection.map(|_| cursor)
 4701                })
 4702                .collect();
 4703
 4704            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4705            this.refresh_edit_prediction(true, false, window, cx);
 4706        });
 4707    }
 4708
 4709    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4710        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4711
 4712        let buffer = self.buffer.read(cx);
 4713        let snapshot = buffer.snapshot(cx);
 4714
 4715        let mut edits = Vec::new();
 4716        let mut rows = Vec::new();
 4717
 4718        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4719            let cursor = selection.head();
 4720            let row = cursor.row;
 4721
 4722            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4723
 4724            let newline = "\n".to_string();
 4725            edits.push((start_of_line..start_of_line, newline));
 4726
 4727            rows.push(row + rows_inserted as u32);
 4728        }
 4729
 4730        self.transact(window, cx, |editor, window, cx| {
 4731            editor.edit(edits, cx);
 4732
 4733            editor.change_selections(Default::default(), window, cx, |s| {
 4734                let mut index = 0;
 4735                s.move_cursors_with(|map, _, _| {
 4736                    let row = rows[index];
 4737                    index += 1;
 4738
 4739                    let point = Point::new(row, 0);
 4740                    let boundary = map.next_line_boundary(point).1;
 4741                    let clipped = map.clip_point(boundary, Bias::Left);
 4742
 4743                    (clipped, SelectionGoal::None)
 4744                });
 4745            });
 4746
 4747            let mut indent_edits = Vec::new();
 4748            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4749            for row in rows {
 4750                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4751                for (row, indent) in indents {
 4752                    if indent.len == 0 {
 4753                        continue;
 4754                    }
 4755
 4756                    let text = match indent.kind {
 4757                        IndentKind::Space => " ".repeat(indent.len as usize),
 4758                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4759                    };
 4760                    let point = Point::new(row.0, 0);
 4761                    indent_edits.push((point..point, text));
 4762                }
 4763            }
 4764            editor.edit(indent_edits, cx);
 4765        });
 4766    }
 4767
 4768    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4769        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4770
 4771        let buffer = self.buffer.read(cx);
 4772        let snapshot = buffer.snapshot(cx);
 4773
 4774        let mut edits = Vec::new();
 4775        let mut rows = Vec::new();
 4776        let mut rows_inserted = 0;
 4777
 4778        for selection in self.selections.all_adjusted(cx) {
 4779            let cursor = selection.head();
 4780            let row = cursor.row;
 4781
 4782            let point = Point::new(row + 1, 0);
 4783            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4784
 4785            let newline = "\n".to_string();
 4786            edits.push((start_of_line..start_of_line, newline));
 4787
 4788            rows_inserted += 1;
 4789            rows.push(row + rows_inserted);
 4790        }
 4791
 4792        self.transact(window, cx, |editor, window, cx| {
 4793            editor.edit(edits, cx);
 4794
 4795            editor.change_selections(Default::default(), window, cx, |s| {
 4796                let mut index = 0;
 4797                s.move_cursors_with(|map, _, _| {
 4798                    let row = rows[index];
 4799                    index += 1;
 4800
 4801                    let point = Point::new(row, 0);
 4802                    let boundary = map.next_line_boundary(point).1;
 4803                    let clipped = map.clip_point(boundary, Bias::Left);
 4804
 4805                    (clipped, SelectionGoal::None)
 4806                });
 4807            });
 4808
 4809            let mut indent_edits = Vec::new();
 4810            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4811            for row in rows {
 4812                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4813                for (row, indent) in indents {
 4814                    if indent.len == 0 {
 4815                        continue;
 4816                    }
 4817
 4818                    let text = match indent.kind {
 4819                        IndentKind::Space => " ".repeat(indent.len as usize),
 4820                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4821                    };
 4822                    let point = Point::new(row.0, 0);
 4823                    indent_edits.push((point..point, text));
 4824                }
 4825            }
 4826            editor.edit(indent_edits, cx);
 4827        });
 4828    }
 4829
 4830    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4831        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4832            original_indent_columns: Vec::new(),
 4833        });
 4834        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4835    }
 4836
 4837    fn insert_with_autoindent_mode(
 4838        &mut self,
 4839        text: &str,
 4840        autoindent_mode: Option<AutoindentMode>,
 4841        window: &mut Window,
 4842        cx: &mut Context<Self>,
 4843    ) {
 4844        if self.read_only(cx) {
 4845            return;
 4846        }
 4847
 4848        let text: Arc<str> = text.into();
 4849        self.transact(window, cx, |this, window, cx| {
 4850            let old_selections = this.selections.all_adjusted(cx);
 4851            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4852                let anchors = {
 4853                    let snapshot = buffer.read(cx);
 4854                    old_selections
 4855                        .iter()
 4856                        .map(|s| {
 4857                            let anchor = snapshot.anchor_after(s.head());
 4858                            s.map(|_| anchor)
 4859                        })
 4860                        .collect::<Vec<_>>()
 4861                };
 4862                buffer.edit(
 4863                    old_selections
 4864                        .iter()
 4865                        .map(|s| (s.start..s.end, text.clone())),
 4866                    autoindent_mode,
 4867                    cx,
 4868                );
 4869                anchors
 4870            });
 4871
 4872            this.change_selections(Default::default(), window, cx, |s| {
 4873                s.select_anchors(selection_anchors);
 4874            });
 4875
 4876            cx.notify();
 4877        });
 4878    }
 4879
 4880    fn trigger_completion_on_input(
 4881        &mut self,
 4882        text: &str,
 4883        trigger_in_words: bool,
 4884        window: &mut Window,
 4885        cx: &mut Context<Self>,
 4886    ) {
 4887        let completions_source = self
 4888            .context_menu
 4889            .borrow()
 4890            .as_ref()
 4891            .and_then(|menu| match menu {
 4892                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4893                CodeContextMenu::CodeActions(_) => None,
 4894            });
 4895
 4896        match completions_source {
 4897            Some(CompletionsMenuSource::Words { .. }) => {
 4898                self.open_or_update_completions_menu(
 4899                    Some(CompletionsMenuSource::Words {
 4900                        ignore_threshold: false,
 4901                    }),
 4902                    None,
 4903                    window,
 4904                    cx,
 4905                );
 4906            }
 4907            Some(CompletionsMenuSource::Normal)
 4908            | Some(CompletionsMenuSource::SnippetChoices)
 4909            | None
 4910                if self.is_completion_trigger(
 4911                    text,
 4912                    trigger_in_words,
 4913                    completions_source.is_some(),
 4914                    cx,
 4915                ) =>
 4916            {
 4917                self.show_completions(
 4918                    &ShowCompletions {
 4919                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4920                    },
 4921                    window,
 4922                    cx,
 4923                )
 4924            }
 4925            _ => {
 4926                self.hide_context_menu(window, cx);
 4927            }
 4928        }
 4929    }
 4930
 4931    fn is_completion_trigger(
 4932        &self,
 4933        text: &str,
 4934        trigger_in_words: bool,
 4935        menu_is_open: bool,
 4936        cx: &mut Context<Self>,
 4937    ) -> bool {
 4938        let position = self.selections.newest_anchor().head();
 4939        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4940            return false;
 4941        };
 4942
 4943        if let Some(completion_provider) = &self.completion_provider {
 4944            completion_provider.is_completion_trigger(
 4945                &buffer,
 4946                position.text_anchor,
 4947                text,
 4948                trigger_in_words,
 4949                menu_is_open,
 4950                cx,
 4951            )
 4952        } else {
 4953            false
 4954        }
 4955    }
 4956
 4957    /// If any empty selections is touching the start of its innermost containing autoclose
 4958    /// region, expand it to select the brackets.
 4959    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4960        let selections = self.selections.all::<usize>(cx);
 4961        let buffer = self.buffer.read(cx).read(cx);
 4962        let new_selections = self
 4963            .selections_with_autoclose_regions(selections, &buffer)
 4964            .map(|(mut selection, region)| {
 4965                if !selection.is_empty() {
 4966                    return selection;
 4967                }
 4968
 4969                if let Some(region) = region {
 4970                    let mut range = region.range.to_offset(&buffer);
 4971                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4972                        range.start -= region.pair.start.len();
 4973                        if buffer.contains_str_at(range.start, &region.pair.start)
 4974                            && buffer.contains_str_at(range.end, &region.pair.end)
 4975                        {
 4976                            range.end += region.pair.end.len();
 4977                            selection.start = range.start;
 4978                            selection.end = range.end;
 4979
 4980                            return selection;
 4981                        }
 4982                    }
 4983                }
 4984
 4985                let always_treat_brackets_as_autoclosed = buffer
 4986                    .language_settings_at(selection.start, cx)
 4987                    .always_treat_brackets_as_autoclosed;
 4988
 4989                if !always_treat_brackets_as_autoclosed {
 4990                    return selection;
 4991                }
 4992
 4993                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4994                    for (pair, enabled) in scope.brackets() {
 4995                        if !enabled || !pair.close {
 4996                            continue;
 4997                        }
 4998
 4999                        if buffer.contains_str_at(selection.start, &pair.end) {
 5000                            let pair_start_len = pair.start.len();
 5001                            if buffer.contains_str_at(
 5002                                selection.start.saturating_sub(pair_start_len),
 5003                                &pair.start,
 5004                            ) {
 5005                                selection.start -= pair_start_len;
 5006                                selection.end += pair.end.len();
 5007
 5008                                return selection;
 5009                            }
 5010                        }
 5011                    }
 5012                }
 5013
 5014                selection
 5015            })
 5016            .collect();
 5017
 5018        drop(buffer);
 5019        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5020            selections.select(new_selections)
 5021        });
 5022    }
 5023
 5024    /// Iterate the given selections, and for each one, find the smallest surrounding
 5025    /// autoclose region. This uses the ordering of the selections and the autoclose
 5026    /// regions to avoid repeated comparisons.
 5027    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5028        &'a self,
 5029        selections: impl IntoIterator<Item = Selection<D>>,
 5030        buffer: &'a MultiBufferSnapshot,
 5031    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5032        let mut i = 0;
 5033        let mut regions = self.autoclose_regions.as_slice();
 5034        selections.into_iter().map(move |selection| {
 5035            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5036
 5037            let mut enclosing = None;
 5038            while let Some(pair_state) = regions.get(i) {
 5039                if pair_state.range.end.to_offset(buffer) < range.start {
 5040                    regions = &regions[i + 1..];
 5041                    i = 0;
 5042                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5043                    break;
 5044                } else {
 5045                    if pair_state.selection_id == selection.id {
 5046                        enclosing = Some(pair_state);
 5047                    }
 5048                    i += 1;
 5049                }
 5050            }
 5051
 5052            (selection, enclosing)
 5053        })
 5054    }
 5055
 5056    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5057    fn invalidate_autoclose_regions(
 5058        &mut self,
 5059        mut selections: &[Selection<Anchor>],
 5060        buffer: &MultiBufferSnapshot,
 5061    ) {
 5062        self.autoclose_regions.retain(|state| {
 5063            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5064                return false;
 5065            }
 5066
 5067            let mut i = 0;
 5068            while let Some(selection) = selections.get(i) {
 5069                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5070                    selections = &selections[1..];
 5071                    continue;
 5072                }
 5073                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5074                    break;
 5075                }
 5076                if selection.id == state.selection_id {
 5077                    return true;
 5078                } else {
 5079                    i += 1;
 5080                }
 5081            }
 5082            false
 5083        });
 5084    }
 5085
 5086    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5087        let offset = position.to_offset(buffer);
 5088        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5089        if offset > word_range.start && kind == Some(CharKind::Word) {
 5090            Some(
 5091                buffer
 5092                    .text_for_range(word_range.start..offset)
 5093                    .collect::<String>(),
 5094            )
 5095        } else {
 5096            None
 5097        }
 5098    }
 5099
 5100    pub fn toggle_inline_values(
 5101        &mut self,
 5102        _: &ToggleInlineValues,
 5103        _: &mut Window,
 5104        cx: &mut Context<Self>,
 5105    ) {
 5106        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5107
 5108        self.refresh_inline_values(cx);
 5109    }
 5110
 5111    pub fn toggle_inlay_hints(
 5112        &mut self,
 5113        _: &ToggleInlayHints,
 5114        _: &mut Window,
 5115        cx: &mut Context<Self>,
 5116    ) {
 5117        self.refresh_inlay_hints(
 5118            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5119            cx,
 5120        );
 5121    }
 5122
 5123    pub fn inlay_hints_enabled(&self) -> bool {
 5124        self.inlay_hint_cache.enabled
 5125    }
 5126
 5127    pub fn inline_values_enabled(&self) -> bool {
 5128        self.inline_value_cache.enabled
 5129    }
 5130
 5131    #[cfg(any(test, feature = "test-support"))]
 5132    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5133        self.display_map
 5134            .read(cx)
 5135            .current_inlays()
 5136            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5137            .cloned()
 5138            .collect()
 5139    }
 5140
 5141    #[cfg(any(test, feature = "test-support"))]
 5142    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5143        self.display_map
 5144            .read(cx)
 5145            .current_inlays()
 5146            .cloned()
 5147            .collect()
 5148    }
 5149
 5150    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5151        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5152            return;
 5153        }
 5154
 5155        let reason_description = reason.description();
 5156        let ignore_debounce = matches!(
 5157            reason,
 5158            InlayHintRefreshReason::SettingsChange(_)
 5159                | InlayHintRefreshReason::Toggle(_)
 5160                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5161                | InlayHintRefreshReason::ModifiersChanged(_)
 5162        );
 5163        let (invalidate_cache, required_languages) = match reason {
 5164            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5165                match self.inlay_hint_cache.modifiers_override(enabled) {
 5166                    Some(enabled) => {
 5167                        if enabled {
 5168                            (InvalidationStrategy::RefreshRequested, None)
 5169                        } else {
 5170                            self.splice_inlays(
 5171                                &self
 5172                                    .visible_inlay_hints(cx)
 5173                                    .iter()
 5174                                    .map(|inlay| inlay.id)
 5175                                    .collect::<Vec<InlayId>>(),
 5176                                Vec::new(),
 5177                                cx,
 5178                            );
 5179                            return;
 5180                        }
 5181                    }
 5182                    None => return,
 5183                }
 5184            }
 5185            InlayHintRefreshReason::Toggle(enabled) => {
 5186                if self.inlay_hint_cache.toggle(enabled) {
 5187                    if enabled {
 5188                        (InvalidationStrategy::RefreshRequested, None)
 5189                    } else {
 5190                        self.splice_inlays(
 5191                            &self
 5192                                .visible_inlay_hints(cx)
 5193                                .iter()
 5194                                .map(|inlay| inlay.id)
 5195                                .collect::<Vec<InlayId>>(),
 5196                            Vec::new(),
 5197                            cx,
 5198                        );
 5199                        return;
 5200                    }
 5201                } else {
 5202                    return;
 5203                }
 5204            }
 5205            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5206                match self.inlay_hint_cache.update_settings(
 5207                    &self.buffer,
 5208                    new_settings,
 5209                    self.visible_inlay_hints(cx),
 5210                    cx,
 5211                ) {
 5212                    ControlFlow::Break(Some(InlaySplice {
 5213                        to_remove,
 5214                        to_insert,
 5215                    })) => {
 5216                        self.splice_inlays(&to_remove, to_insert, cx);
 5217                        return;
 5218                    }
 5219                    ControlFlow::Break(None) => return,
 5220                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5221                }
 5222            }
 5223            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5224                if let Some(InlaySplice {
 5225                    to_remove,
 5226                    to_insert,
 5227                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5228                {
 5229                    self.splice_inlays(&to_remove, to_insert, cx);
 5230                }
 5231                self.display_map.update(cx, |display_map, _| {
 5232                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5233                });
 5234                return;
 5235            }
 5236            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5237            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5238                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5239            }
 5240            InlayHintRefreshReason::RefreshRequested => {
 5241                (InvalidationStrategy::RefreshRequested, None)
 5242            }
 5243        };
 5244
 5245        if let Some(InlaySplice {
 5246            to_remove,
 5247            to_insert,
 5248        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5249            reason_description,
 5250            self.visible_excerpts(required_languages.as_ref(), cx),
 5251            invalidate_cache,
 5252            ignore_debounce,
 5253            cx,
 5254        ) {
 5255            self.splice_inlays(&to_remove, to_insert, cx);
 5256        }
 5257    }
 5258
 5259    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5260        self.display_map
 5261            .read(cx)
 5262            .current_inlays()
 5263            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5264            .cloned()
 5265            .collect()
 5266    }
 5267
 5268    pub fn visible_excerpts(
 5269        &self,
 5270        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5271        cx: &mut Context<Editor>,
 5272    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5273        let Some(project) = self.project() else {
 5274            return HashMap::default();
 5275        };
 5276        let project = project.read(cx);
 5277        let multi_buffer = self.buffer().read(cx);
 5278        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5279        let multi_buffer_visible_start = self
 5280            .scroll_manager
 5281            .anchor()
 5282            .anchor
 5283            .to_point(&multi_buffer_snapshot);
 5284        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5285            multi_buffer_visible_start
 5286                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5287            Bias::Left,
 5288        );
 5289        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5290        multi_buffer_snapshot
 5291            .range_to_buffer_ranges(multi_buffer_visible_range)
 5292            .into_iter()
 5293            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5294            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5295                let buffer_file = project::File::from_dyn(buffer.file())?;
 5296                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5297                let worktree_entry = buffer_worktree
 5298                    .read(cx)
 5299                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5300                if worktree_entry.is_ignored {
 5301                    return None;
 5302                }
 5303
 5304                let language = buffer.language()?;
 5305                if let Some(restrict_to_languages) = restrict_to_languages
 5306                    && !restrict_to_languages.contains(language)
 5307                {
 5308                    return None;
 5309                }
 5310                Some((
 5311                    excerpt_id,
 5312                    (
 5313                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5314                        buffer.version().clone(),
 5315                        excerpt_visible_range,
 5316                    ),
 5317                ))
 5318            })
 5319            .collect()
 5320    }
 5321
 5322    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5323        TextLayoutDetails {
 5324            text_system: window.text_system().clone(),
 5325            editor_style: self.style.clone().unwrap(),
 5326            rem_size: window.rem_size(),
 5327            scroll_anchor: self.scroll_manager.anchor(),
 5328            visible_rows: self.visible_line_count(),
 5329            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5330        }
 5331    }
 5332
 5333    pub fn splice_inlays(
 5334        &self,
 5335        to_remove: &[InlayId],
 5336        to_insert: Vec<Inlay>,
 5337        cx: &mut Context<Self>,
 5338    ) {
 5339        self.display_map.update(cx, |display_map, cx| {
 5340            display_map.splice_inlays(to_remove, to_insert, cx)
 5341        });
 5342        cx.notify();
 5343    }
 5344
 5345    fn trigger_on_type_formatting(
 5346        &self,
 5347        input: String,
 5348        window: &mut Window,
 5349        cx: &mut Context<Self>,
 5350    ) -> Option<Task<Result<()>>> {
 5351        if input.len() != 1 {
 5352            return None;
 5353        }
 5354
 5355        let project = self.project()?;
 5356        let position = self.selections.newest_anchor().head();
 5357        let (buffer, buffer_position) = self
 5358            .buffer
 5359            .read(cx)
 5360            .text_anchor_for_position(position, cx)?;
 5361
 5362        let settings = language_settings::language_settings(
 5363            buffer
 5364                .read(cx)
 5365                .language_at(buffer_position)
 5366                .map(|l| l.name()),
 5367            buffer.read(cx).file(),
 5368            cx,
 5369        );
 5370        if !settings.use_on_type_format {
 5371            return None;
 5372        }
 5373
 5374        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5375        // hence we do LSP request & edit on host side only — add formats to host's history.
 5376        let push_to_lsp_host_history = true;
 5377        // If this is not the host, append its history with new edits.
 5378        let push_to_client_history = project.read(cx).is_via_collab();
 5379
 5380        let on_type_formatting = project.update(cx, |project, cx| {
 5381            project.on_type_format(
 5382                buffer.clone(),
 5383                buffer_position,
 5384                input,
 5385                push_to_lsp_host_history,
 5386                cx,
 5387            )
 5388        });
 5389        Some(cx.spawn_in(window, async move |editor, cx| {
 5390            if let Some(transaction) = on_type_formatting.await? {
 5391                if push_to_client_history {
 5392                    buffer
 5393                        .update(cx, |buffer, _| {
 5394                            buffer.push_transaction(transaction, Instant::now());
 5395                            buffer.finalize_last_transaction();
 5396                        })
 5397                        .ok();
 5398                }
 5399                editor.update(cx, |editor, cx| {
 5400                    editor.refresh_document_highlights(cx);
 5401                })?;
 5402            }
 5403            Ok(())
 5404        }))
 5405    }
 5406
 5407    pub fn show_word_completions(
 5408        &mut self,
 5409        _: &ShowWordCompletions,
 5410        window: &mut Window,
 5411        cx: &mut Context<Self>,
 5412    ) {
 5413        self.open_or_update_completions_menu(
 5414            Some(CompletionsMenuSource::Words {
 5415                ignore_threshold: true,
 5416            }),
 5417            None,
 5418            window,
 5419            cx,
 5420        );
 5421    }
 5422
 5423    pub fn show_completions(
 5424        &mut self,
 5425        options: &ShowCompletions,
 5426        window: &mut Window,
 5427        cx: &mut Context<Self>,
 5428    ) {
 5429        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5430    }
 5431
 5432    fn open_or_update_completions_menu(
 5433        &mut self,
 5434        requested_source: Option<CompletionsMenuSource>,
 5435        trigger: Option<&str>,
 5436        window: &mut Window,
 5437        cx: &mut Context<Self>,
 5438    ) {
 5439        if self.pending_rename.is_some() {
 5440            return;
 5441        }
 5442
 5443        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5444
 5445        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5446        // inserted and selected. To handle that case, the start of the selection is used so that
 5447        // the menu starts with all choices.
 5448        let position = self
 5449            .selections
 5450            .newest_anchor()
 5451            .start
 5452            .bias_right(&multibuffer_snapshot);
 5453        if position.diff_base_anchor.is_some() {
 5454            return;
 5455        }
 5456        let (buffer, buffer_position) =
 5457            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5458                output
 5459            } else {
 5460                return;
 5461            };
 5462        let buffer_snapshot = buffer.read(cx).snapshot();
 5463
 5464        let query: Option<Arc<String>> =
 5465            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5466
 5467        drop(multibuffer_snapshot);
 5468
 5469        let mut ignore_word_threshold = false;
 5470        let provider = match requested_source {
 5471            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5472            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5473                ignore_word_threshold = ignore_threshold;
 5474                None
 5475            }
 5476            Some(CompletionsMenuSource::SnippetChoices) => {
 5477                log::error!("bug: SnippetChoices requested_source is not handled");
 5478                None
 5479            }
 5480        };
 5481
 5482        let sort_completions = provider
 5483            .as_ref()
 5484            .is_some_and(|provider| provider.sort_completions());
 5485
 5486        let filter_completions = provider
 5487            .as_ref()
 5488            .is_none_or(|provider| provider.filter_completions());
 5489
 5490        let trigger_kind = match trigger {
 5491            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5492                CompletionTriggerKind::TRIGGER_CHARACTER
 5493            }
 5494            _ => CompletionTriggerKind::INVOKED,
 5495        };
 5496        let completion_context = CompletionContext {
 5497            trigger_character: trigger.and_then(|trigger| {
 5498                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5499                    Some(String::from(trigger))
 5500                } else {
 5501                    None
 5502                }
 5503            }),
 5504            trigger_kind,
 5505        };
 5506
 5507        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5508        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5509        // involve trigger chars, so this is skipped in that case.
 5510        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5511        {
 5512            let menu_is_open = matches!(
 5513                self.context_menu.borrow().as_ref(),
 5514                Some(CodeContextMenu::Completions(_))
 5515            );
 5516            if menu_is_open {
 5517                self.hide_context_menu(window, cx);
 5518            }
 5519        }
 5520
 5521        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5522            if filter_completions {
 5523                menu.filter(query.clone(), provider.clone(), window, cx);
 5524            }
 5525            // When `is_incomplete` is false, no need to re-query completions when the current query
 5526            // is a suffix of the initial query.
 5527            if !menu.is_incomplete {
 5528                // If the new query is a suffix of the old query (typing more characters) and
 5529                // the previous result was complete, the existing completions can be filtered.
 5530                //
 5531                // Note that this is always true for snippet completions.
 5532                let query_matches = match (&menu.initial_query, &query) {
 5533                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5534                    (None, _) => true,
 5535                    _ => false,
 5536                };
 5537                if query_matches {
 5538                    let position_matches = if menu.initial_position == position {
 5539                        true
 5540                    } else {
 5541                        let snapshot = self.buffer.read(cx).read(cx);
 5542                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5543                    };
 5544                    if position_matches {
 5545                        return;
 5546                    }
 5547                }
 5548            }
 5549        };
 5550
 5551        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5552            buffer_snapshot.surrounding_word(buffer_position, false)
 5553        {
 5554            let word_to_exclude = buffer_snapshot
 5555                .text_for_range(word_range.clone())
 5556                .collect::<String>();
 5557            (
 5558                buffer_snapshot.anchor_before(word_range.start)
 5559                    ..buffer_snapshot.anchor_after(buffer_position),
 5560                Some(word_to_exclude),
 5561            )
 5562        } else {
 5563            (buffer_position..buffer_position, None)
 5564        };
 5565
 5566        let language = buffer_snapshot
 5567            .language_at(buffer_position)
 5568            .map(|language| language.name());
 5569
 5570        let completion_settings =
 5571            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5572
 5573        let show_completion_documentation = buffer_snapshot
 5574            .settings_at(buffer_position, cx)
 5575            .show_completion_documentation;
 5576
 5577        // The document can be large, so stay in reasonable bounds when searching for words,
 5578        // otherwise completion pop-up might be slow to appear.
 5579        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5580        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5581        let min_word_search = buffer_snapshot.clip_point(
 5582            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5583            Bias::Left,
 5584        );
 5585        let max_word_search = buffer_snapshot.clip_point(
 5586            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5587            Bias::Right,
 5588        );
 5589        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5590            ..buffer_snapshot.point_to_offset(max_word_search);
 5591
 5592        let skip_digits = query
 5593            .as_ref()
 5594            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5595
 5596        let omit_word_completions = !self.word_completions_enabled
 5597            || (!ignore_word_threshold
 5598                && match &query {
 5599                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5600                    None => completion_settings.words_min_length != 0,
 5601                });
 5602
 5603        let (mut words, provider_responses) = match &provider {
 5604            Some(provider) => {
 5605                let provider_responses = provider.completions(
 5606                    position.excerpt_id,
 5607                    &buffer,
 5608                    buffer_position,
 5609                    completion_context,
 5610                    window,
 5611                    cx,
 5612                );
 5613
 5614                let words = match (omit_word_completions, completion_settings.words) {
 5615                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5616                        Task::ready(BTreeMap::default())
 5617                    }
 5618                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5619                        .background_spawn(async move {
 5620                            buffer_snapshot.words_in_range(WordsQuery {
 5621                                fuzzy_contents: None,
 5622                                range: word_search_range,
 5623                                skip_digits,
 5624                            })
 5625                        }),
 5626                };
 5627
 5628                (words, provider_responses)
 5629            }
 5630            None => {
 5631                let words = if omit_word_completions {
 5632                    Task::ready(BTreeMap::default())
 5633                } else {
 5634                    cx.background_spawn(async move {
 5635                        buffer_snapshot.words_in_range(WordsQuery {
 5636                            fuzzy_contents: None,
 5637                            range: word_search_range,
 5638                            skip_digits,
 5639                        })
 5640                    })
 5641                };
 5642                (words, Task::ready(Ok(Vec::new())))
 5643            }
 5644        };
 5645
 5646        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5647
 5648        let id = post_inc(&mut self.next_completion_id);
 5649        let task = cx.spawn_in(window, async move |editor, cx| {
 5650            let Ok(()) = editor.update(cx, |this, _| {
 5651                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5652            }) else {
 5653                return;
 5654            };
 5655
 5656            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5657            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5658            let mut completions = Vec::new();
 5659            let mut is_incomplete = false;
 5660            let mut display_options: Option<CompletionDisplayOptions> = None;
 5661            if let Some(provider_responses) = provider_responses.await.log_err()
 5662                && !provider_responses.is_empty()
 5663            {
 5664                for response in provider_responses {
 5665                    completions.extend(response.completions);
 5666                    is_incomplete = is_incomplete || response.is_incomplete;
 5667                    match display_options.as_mut() {
 5668                        None => {
 5669                            display_options = Some(response.display_options);
 5670                        }
 5671                        Some(options) => options.merge(&response.display_options),
 5672                    }
 5673                }
 5674                if completion_settings.words == WordsCompletionMode::Fallback {
 5675                    words = Task::ready(BTreeMap::default());
 5676                }
 5677            }
 5678            let display_options = display_options.unwrap_or_default();
 5679
 5680            let mut words = words.await;
 5681            if let Some(word_to_exclude) = &word_to_exclude {
 5682                words.remove(word_to_exclude);
 5683            }
 5684            for lsp_completion in &completions {
 5685                words.remove(&lsp_completion.new_text);
 5686            }
 5687            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5688                replace_range: word_replace_range.clone(),
 5689                new_text: word.clone(),
 5690                label: CodeLabel::plain(word, None),
 5691                icon_path: None,
 5692                documentation: None,
 5693                source: CompletionSource::BufferWord {
 5694                    word_range,
 5695                    resolved: false,
 5696                },
 5697                insert_text_mode: Some(InsertTextMode::AS_IS),
 5698                confirm: None,
 5699            }));
 5700
 5701            let menu = if completions.is_empty() {
 5702                None
 5703            } else {
 5704                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5705                    let languages = editor
 5706                        .workspace
 5707                        .as_ref()
 5708                        .and_then(|(workspace, _)| workspace.upgrade())
 5709                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5710                    let menu = CompletionsMenu::new(
 5711                        id,
 5712                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5713                        sort_completions,
 5714                        show_completion_documentation,
 5715                        position,
 5716                        query.clone(),
 5717                        is_incomplete,
 5718                        buffer.clone(),
 5719                        completions.into(),
 5720                        display_options,
 5721                        snippet_sort_order,
 5722                        languages,
 5723                        language,
 5724                        cx,
 5725                    );
 5726
 5727                    let query = if filter_completions { query } else { None };
 5728                    let matches_task = if let Some(query) = query {
 5729                        menu.do_async_filtering(query, cx)
 5730                    } else {
 5731                        Task::ready(menu.unfiltered_matches())
 5732                    };
 5733                    (menu, matches_task)
 5734                }) else {
 5735                    return;
 5736                };
 5737
 5738                let matches = matches_task.await;
 5739
 5740                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5741                    // Newer menu already set, so exit.
 5742                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5743                        editor.context_menu.borrow().as_ref()
 5744                        && prev_menu.id > id
 5745                    {
 5746                        return;
 5747                    };
 5748
 5749                    // Only valid to take prev_menu because it the new menu is immediately set
 5750                    // below, or the menu is hidden.
 5751                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5752                        editor.context_menu.borrow_mut().take()
 5753                    {
 5754                        let position_matches =
 5755                            if prev_menu.initial_position == menu.initial_position {
 5756                                true
 5757                            } else {
 5758                                let snapshot = editor.buffer.read(cx).read(cx);
 5759                                prev_menu.initial_position.to_offset(&snapshot)
 5760                                    == menu.initial_position.to_offset(&snapshot)
 5761                            };
 5762                        if position_matches {
 5763                            // Preserve markdown cache before `set_filter_results` because it will
 5764                            // try to populate the documentation cache.
 5765                            menu.preserve_markdown_cache(prev_menu);
 5766                        }
 5767                    };
 5768
 5769                    menu.set_filter_results(matches, provider, window, cx);
 5770                }) else {
 5771                    return;
 5772                };
 5773
 5774                menu.visible().then_some(menu)
 5775            };
 5776
 5777            editor
 5778                .update_in(cx, |editor, window, cx| {
 5779                    if editor.focus_handle.is_focused(window)
 5780                        && let Some(menu) = menu
 5781                    {
 5782                        *editor.context_menu.borrow_mut() =
 5783                            Some(CodeContextMenu::Completions(menu));
 5784
 5785                        crate::hover_popover::hide_hover(editor, cx);
 5786                        if editor.show_edit_predictions_in_menu() {
 5787                            editor.update_visible_edit_prediction(window, cx);
 5788                        } else {
 5789                            editor.discard_edit_prediction(false, cx);
 5790                        }
 5791
 5792                        cx.notify();
 5793                        return;
 5794                    }
 5795
 5796                    if editor.completion_tasks.len() <= 1 {
 5797                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5798                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5799                        // If it was already hidden and we don't show edit predictions in the menu,
 5800                        // we should also show the edit prediction when available.
 5801                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5802                            editor.update_visible_edit_prediction(window, cx);
 5803                        }
 5804                    }
 5805                })
 5806                .ok();
 5807        });
 5808
 5809        self.completion_tasks.push((id, task));
 5810    }
 5811
 5812    #[cfg(feature = "test-support")]
 5813    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5814        let menu = self.context_menu.borrow();
 5815        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5816            let completions = menu.completions.borrow();
 5817            Some(completions.to_vec())
 5818        } else {
 5819            None
 5820        }
 5821    }
 5822
 5823    pub fn with_completions_menu_matching_id<R>(
 5824        &self,
 5825        id: CompletionId,
 5826        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5827    ) -> R {
 5828        let mut context_menu = self.context_menu.borrow_mut();
 5829        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5830            return f(None);
 5831        };
 5832        if completions_menu.id != id {
 5833            return f(None);
 5834        }
 5835        f(Some(completions_menu))
 5836    }
 5837
 5838    pub fn confirm_completion(
 5839        &mut self,
 5840        action: &ConfirmCompletion,
 5841        window: &mut Window,
 5842        cx: &mut Context<Self>,
 5843    ) -> Option<Task<Result<()>>> {
 5844        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5845        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5846    }
 5847
 5848    pub fn confirm_completion_insert(
 5849        &mut self,
 5850        _: &ConfirmCompletionInsert,
 5851        window: &mut Window,
 5852        cx: &mut Context<Self>,
 5853    ) -> Option<Task<Result<()>>> {
 5854        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5855        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5856    }
 5857
 5858    pub fn confirm_completion_replace(
 5859        &mut self,
 5860        _: &ConfirmCompletionReplace,
 5861        window: &mut Window,
 5862        cx: &mut Context<Self>,
 5863    ) -> Option<Task<Result<()>>> {
 5864        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5865        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5866    }
 5867
 5868    pub fn compose_completion(
 5869        &mut self,
 5870        action: &ComposeCompletion,
 5871        window: &mut Window,
 5872        cx: &mut Context<Self>,
 5873    ) -> Option<Task<Result<()>>> {
 5874        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5875        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5876    }
 5877
 5878    fn do_completion(
 5879        &mut self,
 5880        item_ix: Option<usize>,
 5881        intent: CompletionIntent,
 5882        window: &mut Window,
 5883        cx: &mut Context<Editor>,
 5884    ) -> Option<Task<Result<()>>> {
 5885        use language::ToOffset as _;
 5886
 5887        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5888        else {
 5889            return None;
 5890        };
 5891
 5892        let candidate_id = {
 5893            let entries = completions_menu.entries.borrow();
 5894            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5895            if self.show_edit_predictions_in_menu() {
 5896                self.discard_edit_prediction(true, cx);
 5897            }
 5898            mat.candidate_id
 5899        };
 5900
 5901        let completion = completions_menu
 5902            .completions
 5903            .borrow()
 5904            .get(candidate_id)?
 5905            .clone();
 5906        cx.stop_propagation();
 5907
 5908        let buffer_handle = completions_menu.buffer.clone();
 5909
 5910        let CompletionEdit {
 5911            new_text,
 5912            snippet,
 5913            replace_range,
 5914        } = process_completion_for_edit(
 5915            &completion,
 5916            intent,
 5917            &buffer_handle,
 5918            &completions_menu.initial_position.text_anchor,
 5919            cx,
 5920        );
 5921
 5922        let buffer = buffer_handle.read(cx);
 5923        let snapshot = self.buffer.read(cx).snapshot(cx);
 5924        let newest_anchor = self.selections.newest_anchor();
 5925        let replace_range_multibuffer = {
 5926            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5927            let multibuffer_anchor = snapshot
 5928                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5929                .unwrap()
 5930                ..snapshot
 5931                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5932                    .unwrap();
 5933            multibuffer_anchor.start.to_offset(&snapshot)
 5934                ..multibuffer_anchor.end.to_offset(&snapshot)
 5935        };
 5936        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5937            return None;
 5938        }
 5939
 5940        let old_text = buffer
 5941            .text_for_range(replace_range.clone())
 5942            .collect::<String>();
 5943        let lookbehind = newest_anchor
 5944            .start
 5945            .text_anchor
 5946            .to_offset(buffer)
 5947            .saturating_sub(replace_range.start);
 5948        let lookahead = replace_range
 5949            .end
 5950            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5951        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5952        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5953
 5954        let selections = self.selections.all::<usize>(cx);
 5955        let mut ranges = Vec::new();
 5956        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5957
 5958        for selection in &selections {
 5959            let range = if selection.id == newest_anchor.id {
 5960                replace_range_multibuffer.clone()
 5961            } else {
 5962                let mut range = selection.range();
 5963
 5964                // if prefix is present, don't duplicate it
 5965                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5966                    range.start = range.start.saturating_sub(lookbehind);
 5967
 5968                    // if suffix is also present, mimic the newest cursor and replace it
 5969                    if selection.id != newest_anchor.id
 5970                        && snapshot.contains_str_at(range.end, suffix)
 5971                    {
 5972                        range.end += lookahead;
 5973                    }
 5974                }
 5975                range
 5976            };
 5977
 5978            ranges.push(range.clone());
 5979
 5980            if !self.linked_edit_ranges.is_empty() {
 5981                let start_anchor = snapshot.anchor_before(range.start);
 5982                let end_anchor = snapshot.anchor_after(range.end);
 5983                if let Some(ranges) = self
 5984                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5985                {
 5986                    for (buffer, edits) in ranges {
 5987                        linked_edits
 5988                            .entry(buffer.clone())
 5989                            .or_default()
 5990                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5991                    }
 5992                }
 5993            }
 5994        }
 5995
 5996        let common_prefix_len = old_text
 5997            .chars()
 5998            .zip(new_text.chars())
 5999            .take_while(|(a, b)| a == b)
 6000            .map(|(a, _)| a.len_utf8())
 6001            .sum::<usize>();
 6002
 6003        cx.emit(EditorEvent::InputHandled {
 6004            utf16_range_to_replace: None,
 6005            text: new_text[common_prefix_len..].into(),
 6006        });
 6007
 6008        self.transact(window, cx, |editor, window, cx| {
 6009            if let Some(mut snippet) = snippet {
 6010                snippet.text = new_text.to_string();
 6011                editor
 6012                    .insert_snippet(&ranges, snippet, window, cx)
 6013                    .log_err();
 6014            } else {
 6015                editor.buffer.update(cx, |multi_buffer, cx| {
 6016                    let auto_indent = match completion.insert_text_mode {
 6017                        Some(InsertTextMode::AS_IS) => None,
 6018                        _ => editor.autoindent_mode.clone(),
 6019                    };
 6020                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6021                    multi_buffer.edit(edits, auto_indent, cx);
 6022                });
 6023            }
 6024            for (buffer, edits) in linked_edits {
 6025                buffer.update(cx, |buffer, cx| {
 6026                    let snapshot = buffer.snapshot();
 6027                    let edits = edits
 6028                        .into_iter()
 6029                        .map(|(range, text)| {
 6030                            use text::ToPoint as TP;
 6031                            let end_point = TP::to_point(&range.end, &snapshot);
 6032                            let start_point = TP::to_point(&range.start, &snapshot);
 6033                            (start_point..end_point, text)
 6034                        })
 6035                        .sorted_by_key(|(range, _)| range.start);
 6036                    buffer.edit(edits, None, cx);
 6037                })
 6038            }
 6039
 6040            editor.refresh_edit_prediction(true, false, window, cx);
 6041        });
 6042        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 6043
 6044        let show_new_completions_on_confirm = completion
 6045            .confirm
 6046            .as_ref()
 6047            .is_some_and(|confirm| confirm(intent, window, cx));
 6048        if show_new_completions_on_confirm {
 6049            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6050        }
 6051
 6052        let provider = self.completion_provider.as_ref()?;
 6053        drop(completion);
 6054        let apply_edits = provider.apply_additional_edits_for_completion(
 6055            buffer_handle,
 6056            completions_menu.completions.clone(),
 6057            candidate_id,
 6058            true,
 6059            cx,
 6060        );
 6061
 6062        let editor_settings = EditorSettings::get_global(cx);
 6063        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6064            // After the code completion is finished, users often want to know what signatures are needed.
 6065            // so we should automatically call signature_help
 6066            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6067        }
 6068
 6069        Some(cx.foreground_executor().spawn(async move {
 6070            apply_edits.await?;
 6071            Ok(())
 6072        }))
 6073    }
 6074
 6075    pub fn toggle_code_actions(
 6076        &mut self,
 6077        action: &ToggleCodeActions,
 6078        window: &mut Window,
 6079        cx: &mut Context<Self>,
 6080    ) {
 6081        let quick_launch = action.quick_launch;
 6082        let mut context_menu = self.context_menu.borrow_mut();
 6083        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6084            if code_actions.deployed_from == action.deployed_from {
 6085                // Toggle if we're selecting the same one
 6086                *context_menu = None;
 6087                cx.notify();
 6088                return;
 6089            } else {
 6090                // Otherwise, clear it and start a new one
 6091                *context_menu = None;
 6092                cx.notify();
 6093            }
 6094        }
 6095        drop(context_menu);
 6096        let snapshot = self.snapshot(window, cx);
 6097        let deployed_from = action.deployed_from.clone();
 6098        let action = action.clone();
 6099        self.completion_tasks.clear();
 6100        self.discard_edit_prediction(false, cx);
 6101
 6102        let multibuffer_point = match &action.deployed_from {
 6103            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6104                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6105            }
 6106            _ => self.selections.newest::<Point>(cx).head(),
 6107        };
 6108        let Some((buffer, buffer_row)) = snapshot
 6109            .buffer_snapshot
 6110            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6111            .and_then(|(buffer_snapshot, range)| {
 6112                self.buffer()
 6113                    .read(cx)
 6114                    .buffer(buffer_snapshot.remote_id())
 6115                    .map(|buffer| (buffer, range.start.row))
 6116            })
 6117        else {
 6118            return;
 6119        };
 6120        let buffer_id = buffer.read(cx).remote_id();
 6121        let tasks = self
 6122            .tasks
 6123            .get(&(buffer_id, buffer_row))
 6124            .map(|t| Arc::new(t.to_owned()));
 6125
 6126        if !self.focus_handle.is_focused(window) {
 6127            return;
 6128        }
 6129        let project = self.project.clone();
 6130
 6131        let code_actions_task = match deployed_from {
 6132            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6133            _ => self.code_actions(buffer_row, window, cx),
 6134        };
 6135
 6136        let runnable_task = match deployed_from {
 6137            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6138            _ => {
 6139                let mut task_context_task = Task::ready(None);
 6140                if let Some(tasks) = &tasks
 6141                    && let Some(project) = project
 6142                {
 6143                    task_context_task =
 6144                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6145                }
 6146
 6147                cx.spawn_in(window, {
 6148                    let buffer = buffer.clone();
 6149                    async move |editor, cx| {
 6150                        let task_context = task_context_task.await;
 6151
 6152                        let resolved_tasks =
 6153                            tasks
 6154                                .zip(task_context.clone())
 6155                                .map(|(tasks, task_context)| ResolvedTasks {
 6156                                    templates: tasks.resolve(&task_context).collect(),
 6157                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6158                                        multibuffer_point.row,
 6159                                        tasks.column,
 6160                                    )),
 6161                                });
 6162                        let debug_scenarios = editor
 6163                            .update(cx, |editor, cx| {
 6164                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6165                            })?
 6166                            .await;
 6167                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6168                    }
 6169                })
 6170            }
 6171        };
 6172
 6173        cx.spawn_in(window, async move |editor, cx| {
 6174            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6175            let code_actions = code_actions_task.await;
 6176            let spawn_straight_away = quick_launch
 6177                && resolved_tasks
 6178                    .as_ref()
 6179                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6180                && code_actions
 6181                    .as_ref()
 6182                    .is_none_or(|actions| actions.is_empty())
 6183                && debug_scenarios.is_empty();
 6184
 6185            editor.update_in(cx, |editor, window, cx| {
 6186                crate::hover_popover::hide_hover(editor, cx);
 6187                let actions = CodeActionContents::new(
 6188                    resolved_tasks,
 6189                    code_actions,
 6190                    debug_scenarios,
 6191                    task_context.unwrap_or_default(),
 6192                );
 6193
 6194                // Don't show the menu if there are no actions available
 6195                if actions.is_empty() {
 6196                    cx.notify();
 6197                    return Task::ready(Ok(()));
 6198                }
 6199
 6200                *editor.context_menu.borrow_mut() =
 6201                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6202                        buffer,
 6203                        actions,
 6204                        selected_item: Default::default(),
 6205                        scroll_handle: UniformListScrollHandle::default(),
 6206                        deployed_from,
 6207                    }));
 6208                cx.notify();
 6209                if spawn_straight_away
 6210                    && let Some(task) = editor.confirm_code_action(
 6211                        &ConfirmCodeAction { item_ix: Some(0) },
 6212                        window,
 6213                        cx,
 6214                    )
 6215                {
 6216                    return task;
 6217                }
 6218
 6219                Task::ready(Ok(()))
 6220            })
 6221        })
 6222        .detach_and_log_err(cx);
 6223    }
 6224
 6225    fn debug_scenarios(
 6226        &mut self,
 6227        resolved_tasks: &Option<ResolvedTasks>,
 6228        buffer: &Entity<Buffer>,
 6229        cx: &mut App,
 6230    ) -> Task<Vec<task::DebugScenario>> {
 6231        maybe!({
 6232            let project = self.project()?;
 6233            let dap_store = project.read(cx).dap_store();
 6234            let mut scenarios = vec![];
 6235            let resolved_tasks = resolved_tasks.as_ref()?;
 6236            let buffer = buffer.read(cx);
 6237            let language = buffer.language()?;
 6238            let file = buffer.file();
 6239            let debug_adapter = language_settings(language.name().into(), file, cx)
 6240                .debuggers
 6241                .first()
 6242                .map(SharedString::from)
 6243                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6244
 6245            dap_store.update(cx, |dap_store, cx| {
 6246                for (_, task) in &resolved_tasks.templates {
 6247                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6248                        task.original_task().clone(),
 6249                        debug_adapter.clone().into(),
 6250                        task.display_label().to_owned().into(),
 6251                        cx,
 6252                    );
 6253                    scenarios.push(maybe_scenario);
 6254                }
 6255            });
 6256            Some(cx.background_spawn(async move {
 6257                futures::future::join_all(scenarios)
 6258                    .await
 6259                    .into_iter()
 6260                    .flatten()
 6261                    .collect::<Vec<_>>()
 6262            }))
 6263        })
 6264        .unwrap_or_else(|| Task::ready(vec![]))
 6265    }
 6266
 6267    fn code_actions(
 6268        &mut self,
 6269        buffer_row: u32,
 6270        window: &mut Window,
 6271        cx: &mut Context<Self>,
 6272    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6273        let mut task = self.code_actions_task.take();
 6274        cx.spawn_in(window, async move |editor, cx| {
 6275            while let Some(prev_task) = task {
 6276                prev_task.await.log_err();
 6277                task = editor
 6278                    .update(cx, |this, _| this.code_actions_task.take())
 6279                    .ok()?;
 6280            }
 6281
 6282            editor
 6283                .update(cx, |editor, cx| {
 6284                    editor
 6285                        .available_code_actions
 6286                        .clone()
 6287                        .and_then(|(location, code_actions)| {
 6288                            let snapshot = location.buffer.read(cx).snapshot();
 6289                            let point_range = location.range.to_point(&snapshot);
 6290                            let point_range = point_range.start.row..=point_range.end.row;
 6291                            if point_range.contains(&buffer_row) {
 6292                                Some(code_actions)
 6293                            } else {
 6294                                None
 6295                            }
 6296                        })
 6297                })
 6298                .ok()
 6299                .flatten()
 6300        })
 6301    }
 6302
 6303    pub fn confirm_code_action(
 6304        &mut self,
 6305        action: &ConfirmCodeAction,
 6306        window: &mut Window,
 6307        cx: &mut Context<Self>,
 6308    ) -> Option<Task<Result<()>>> {
 6309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6310
 6311        let actions_menu =
 6312            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6313                menu
 6314            } else {
 6315                return None;
 6316            };
 6317
 6318        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6319        let action = actions_menu.actions.get(action_ix)?;
 6320        let title = action.label();
 6321        let buffer = actions_menu.buffer;
 6322        let workspace = self.workspace()?;
 6323
 6324        match action {
 6325            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6326                workspace.update(cx, |workspace, cx| {
 6327                    workspace.schedule_resolved_task(
 6328                        task_source_kind,
 6329                        resolved_task,
 6330                        false,
 6331                        window,
 6332                        cx,
 6333                    );
 6334
 6335                    Some(Task::ready(Ok(())))
 6336                })
 6337            }
 6338            CodeActionsItem::CodeAction {
 6339                excerpt_id,
 6340                action,
 6341                provider,
 6342            } => {
 6343                let apply_code_action =
 6344                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6345                let workspace = workspace.downgrade();
 6346                Some(cx.spawn_in(window, async move |editor, cx| {
 6347                    let project_transaction = apply_code_action.await?;
 6348                    Self::open_project_transaction(
 6349                        &editor,
 6350                        workspace,
 6351                        project_transaction,
 6352                        title,
 6353                        cx,
 6354                    )
 6355                    .await
 6356                }))
 6357            }
 6358            CodeActionsItem::DebugScenario(scenario) => {
 6359                let context = actions_menu.actions.context;
 6360
 6361                workspace.update(cx, |workspace, cx| {
 6362                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6363                    workspace.start_debug_session(
 6364                        scenario,
 6365                        context,
 6366                        Some(buffer),
 6367                        None,
 6368                        window,
 6369                        cx,
 6370                    );
 6371                });
 6372                Some(Task::ready(Ok(())))
 6373            }
 6374        }
 6375    }
 6376
 6377    pub async fn open_project_transaction(
 6378        editor: &WeakEntity<Editor>,
 6379        workspace: WeakEntity<Workspace>,
 6380        transaction: ProjectTransaction,
 6381        title: String,
 6382        cx: &mut AsyncWindowContext,
 6383    ) -> Result<()> {
 6384        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6385        cx.update(|_, cx| {
 6386            entries.sort_unstable_by_key(|(buffer, _)| {
 6387                buffer.read(cx).file().map(|f| f.path().clone())
 6388            });
 6389        })?;
 6390
 6391        // If the project transaction's edits are all contained within this editor, then
 6392        // avoid opening a new editor to display them.
 6393
 6394        if let Some((buffer, transaction)) = entries.first() {
 6395            if entries.len() == 1 {
 6396                let excerpt = editor.update(cx, |editor, cx| {
 6397                    editor
 6398                        .buffer()
 6399                        .read(cx)
 6400                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6401                })?;
 6402                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6403                    && excerpted_buffer == *buffer
 6404                {
 6405                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6406                        let excerpt_range = excerpt_range.to_offset(buffer);
 6407                        buffer
 6408                            .edited_ranges_for_transaction::<usize>(transaction)
 6409                            .all(|range| {
 6410                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6411                            })
 6412                    })?;
 6413
 6414                    if all_edits_within_excerpt {
 6415                        return Ok(());
 6416                    }
 6417                }
 6418            }
 6419        } else {
 6420            return Ok(());
 6421        }
 6422
 6423        let mut ranges_to_highlight = Vec::new();
 6424        let excerpt_buffer = cx.new(|cx| {
 6425            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6426            for (buffer_handle, transaction) in &entries {
 6427                let edited_ranges = buffer_handle
 6428                    .read(cx)
 6429                    .edited_ranges_for_transaction::<Point>(transaction)
 6430                    .collect::<Vec<_>>();
 6431                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6432                    PathKey::for_buffer(buffer_handle, cx),
 6433                    buffer_handle.clone(),
 6434                    edited_ranges,
 6435                    multibuffer_context_lines(cx),
 6436                    cx,
 6437                );
 6438
 6439                ranges_to_highlight.extend(ranges);
 6440            }
 6441            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6442            multibuffer
 6443        })?;
 6444
 6445        workspace.update_in(cx, |workspace, window, cx| {
 6446            let project = workspace.project().clone();
 6447            let editor =
 6448                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6449            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6450            editor.update(cx, |editor, cx| {
 6451                editor.highlight_background::<Self>(
 6452                    &ranges_to_highlight,
 6453                    |theme| theme.colors().editor_highlighted_line_background,
 6454                    cx,
 6455                );
 6456            });
 6457        })?;
 6458
 6459        Ok(())
 6460    }
 6461
 6462    pub fn clear_code_action_providers(&mut self) {
 6463        self.code_action_providers.clear();
 6464        self.available_code_actions.take();
 6465    }
 6466
 6467    pub fn add_code_action_provider(
 6468        &mut self,
 6469        provider: Rc<dyn CodeActionProvider>,
 6470        window: &mut Window,
 6471        cx: &mut Context<Self>,
 6472    ) {
 6473        if self
 6474            .code_action_providers
 6475            .iter()
 6476            .any(|existing_provider| existing_provider.id() == provider.id())
 6477        {
 6478            return;
 6479        }
 6480
 6481        self.code_action_providers.push(provider);
 6482        self.refresh_code_actions(window, cx);
 6483    }
 6484
 6485    pub fn remove_code_action_provider(
 6486        &mut self,
 6487        id: Arc<str>,
 6488        window: &mut Window,
 6489        cx: &mut Context<Self>,
 6490    ) {
 6491        self.code_action_providers
 6492            .retain(|provider| provider.id() != id);
 6493        self.refresh_code_actions(window, cx);
 6494    }
 6495
 6496    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6497        !self.code_action_providers.is_empty()
 6498            && EditorSettings::get_global(cx).toolbar.code_actions
 6499    }
 6500
 6501    pub fn has_available_code_actions(&self) -> bool {
 6502        self.available_code_actions
 6503            .as_ref()
 6504            .is_some_and(|(_, actions)| !actions.is_empty())
 6505    }
 6506
 6507    fn render_inline_code_actions(
 6508        &self,
 6509        icon_size: ui::IconSize,
 6510        display_row: DisplayRow,
 6511        is_active: bool,
 6512        cx: &mut Context<Self>,
 6513    ) -> AnyElement {
 6514        let show_tooltip = !self.context_menu_visible();
 6515        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6516            .icon_size(icon_size)
 6517            .shape(ui::IconButtonShape::Square)
 6518            .icon_color(ui::Color::Hidden)
 6519            .toggle_state(is_active)
 6520            .when(show_tooltip, |this| {
 6521                this.tooltip({
 6522                    let focus_handle = self.focus_handle.clone();
 6523                    move |window, cx| {
 6524                        Tooltip::for_action_in(
 6525                            "Toggle Code Actions",
 6526                            &ToggleCodeActions {
 6527                                deployed_from: None,
 6528                                quick_launch: false,
 6529                            },
 6530                            &focus_handle,
 6531                            window,
 6532                            cx,
 6533                        )
 6534                    }
 6535                })
 6536            })
 6537            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6538                window.focus(&editor.focus_handle(cx));
 6539                editor.toggle_code_actions(
 6540                    &crate::actions::ToggleCodeActions {
 6541                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6542                            display_row,
 6543                        )),
 6544                        quick_launch: false,
 6545                    },
 6546                    window,
 6547                    cx,
 6548                );
 6549            }))
 6550            .into_any_element()
 6551    }
 6552
 6553    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6554        &self.context_menu
 6555    }
 6556
 6557    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6558        let newest_selection = self.selections.newest_anchor().clone();
 6559        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6560        let buffer = self.buffer.read(cx);
 6561        if newest_selection.head().diff_base_anchor.is_some() {
 6562            return None;
 6563        }
 6564        let (start_buffer, start) =
 6565            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6566        let (end_buffer, end) =
 6567            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6568        if start_buffer != end_buffer {
 6569            return None;
 6570        }
 6571
 6572        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6573            cx.background_executor()
 6574                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6575                .await;
 6576
 6577            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6578                let providers = this.code_action_providers.clone();
 6579                let tasks = this
 6580                    .code_action_providers
 6581                    .iter()
 6582                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6583                    .collect::<Vec<_>>();
 6584                (providers, tasks)
 6585            })?;
 6586
 6587            let mut actions = Vec::new();
 6588            for (provider, provider_actions) in
 6589                providers.into_iter().zip(future::join_all(tasks).await)
 6590            {
 6591                if let Some(provider_actions) = provider_actions.log_err() {
 6592                    actions.extend(provider_actions.into_iter().map(|action| {
 6593                        AvailableCodeAction {
 6594                            excerpt_id: newest_selection.start.excerpt_id,
 6595                            action,
 6596                            provider: provider.clone(),
 6597                        }
 6598                    }));
 6599                }
 6600            }
 6601
 6602            this.update(cx, |this, cx| {
 6603                this.available_code_actions = if actions.is_empty() {
 6604                    None
 6605                } else {
 6606                    Some((
 6607                        Location {
 6608                            buffer: start_buffer,
 6609                            range: start..end,
 6610                        },
 6611                        actions.into(),
 6612                    ))
 6613                };
 6614                cx.notify();
 6615            })
 6616        }));
 6617        None
 6618    }
 6619
 6620    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6621        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6622            self.show_git_blame_inline = false;
 6623
 6624            self.show_git_blame_inline_delay_task =
 6625                Some(cx.spawn_in(window, async move |this, cx| {
 6626                    cx.background_executor().timer(delay).await;
 6627
 6628                    this.update(cx, |this, cx| {
 6629                        this.show_git_blame_inline = true;
 6630                        cx.notify();
 6631                    })
 6632                    .log_err();
 6633                }));
 6634        }
 6635    }
 6636
 6637    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6638        let snapshot = self.snapshot(window, cx);
 6639        let cursor = self.selections.newest::<Point>(cx).head();
 6640        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6641        else {
 6642            return;
 6643        };
 6644
 6645        let Some(blame) = self.blame.as_ref() else {
 6646            return;
 6647        };
 6648
 6649        let row_info = RowInfo {
 6650            buffer_id: Some(buffer.remote_id()),
 6651            buffer_row: Some(point.row),
 6652            ..Default::default()
 6653        };
 6654        let Some((buffer, blame_entry)) = blame
 6655            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6656            .flatten()
 6657        else {
 6658            return;
 6659        };
 6660
 6661        let anchor = self.selections.newest_anchor().head();
 6662        let position = self.to_pixel_point(anchor, &snapshot, window);
 6663        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6664            self.show_blame_popover(
 6665                buffer,
 6666                &blame_entry,
 6667                position + last_bounds.origin,
 6668                true,
 6669                cx,
 6670            );
 6671        };
 6672    }
 6673
 6674    fn show_blame_popover(
 6675        &mut self,
 6676        buffer: BufferId,
 6677        blame_entry: &BlameEntry,
 6678        position: gpui::Point<Pixels>,
 6679        ignore_timeout: bool,
 6680        cx: &mut Context<Self>,
 6681    ) {
 6682        if let Some(state) = &mut self.inline_blame_popover {
 6683            state.hide_task.take();
 6684        } else {
 6685            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6686            let blame_entry = blame_entry.clone();
 6687            let show_task = cx.spawn(async move |editor, cx| {
 6688                if !ignore_timeout {
 6689                    cx.background_executor()
 6690                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6691                        .await;
 6692                }
 6693                editor
 6694                    .update(cx, |editor, cx| {
 6695                        editor.inline_blame_popover_show_task.take();
 6696                        let Some(blame) = editor.blame.as_ref() else {
 6697                            return;
 6698                        };
 6699                        let blame = blame.read(cx);
 6700                        let details = blame.details_for_entry(buffer, &blame_entry);
 6701                        let markdown = cx.new(|cx| {
 6702                            Markdown::new(
 6703                                details
 6704                                    .as_ref()
 6705                                    .map(|message| message.message.clone())
 6706                                    .unwrap_or_default(),
 6707                                None,
 6708                                None,
 6709                                cx,
 6710                            )
 6711                        });
 6712                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6713                            position,
 6714                            hide_task: None,
 6715                            popover_bounds: None,
 6716                            popover_state: InlineBlamePopoverState {
 6717                                scroll_handle: ScrollHandle::new(),
 6718                                commit_message: details,
 6719                                markdown,
 6720                            },
 6721                            keyboard_grace: ignore_timeout,
 6722                        });
 6723                        cx.notify();
 6724                    })
 6725                    .ok();
 6726            });
 6727            self.inline_blame_popover_show_task = Some(show_task);
 6728        }
 6729    }
 6730
 6731    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6732        self.inline_blame_popover_show_task.take();
 6733        if let Some(state) = &mut self.inline_blame_popover {
 6734            let hide_task = cx.spawn(async move |editor, cx| {
 6735                cx.background_executor()
 6736                    .timer(std::time::Duration::from_millis(100))
 6737                    .await;
 6738                editor
 6739                    .update(cx, |editor, cx| {
 6740                        editor.inline_blame_popover.take();
 6741                        cx.notify();
 6742                    })
 6743                    .ok();
 6744            });
 6745            state.hide_task = Some(hide_task);
 6746        }
 6747    }
 6748
 6749    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6750        if self.pending_rename.is_some() {
 6751            return None;
 6752        }
 6753
 6754        let provider = self.semantics_provider.clone()?;
 6755        let buffer = self.buffer.read(cx);
 6756        let newest_selection = self.selections.newest_anchor().clone();
 6757        let cursor_position = newest_selection.head();
 6758        let (cursor_buffer, cursor_buffer_position) =
 6759            buffer.text_anchor_for_position(cursor_position, cx)?;
 6760        let (tail_buffer, tail_buffer_position) =
 6761            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6762        if cursor_buffer != tail_buffer {
 6763            return None;
 6764        }
 6765
 6766        let snapshot = cursor_buffer.read(cx).snapshot();
 6767        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6768        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6769        if start_word_range != end_word_range {
 6770            self.document_highlights_task.take();
 6771            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6772            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6773            return None;
 6774        }
 6775
 6776        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6777        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6778            cx.background_executor()
 6779                .timer(Duration::from_millis(debounce))
 6780                .await;
 6781
 6782            let highlights = if let Some(highlights) = cx
 6783                .update(|cx| {
 6784                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6785                })
 6786                .ok()
 6787                .flatten()
 6788            {
 6789                highlights.await.log_err()
 6790            } else {
 6791                None
 6792            };
 6793
 6794            if let Some(highlights) = highlights {
 6795                this.update(cx, |this, cx| {
 6796                    if this.pending_rename.is_some() {
 6797                        return;
 6798                    }
 6799
 6800                    let buffer = this.buffer.read(cx);
 6801                    if buffer
 6802                        .text_anchor_for_position(cursor_position, cx)
 6803                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6804                    {
 6805                        return;
 6806                    }
 6807
 6808                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6809                    let mut write_ranges = Vec::new();
 6810                    let mut read_ranges = Vec::new();
 6811                    for highlight in highlights {
 6812                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6813                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6814                        {
 6815                            let start = highlight
 6816                                .range
 6817                                .start
 6818                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6819                            let end = highlight
 6820                                .range
 6821                                .end
 6822                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6823                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6824                                continue;
 6825                            }
 6826
 6827                            let range = Anchor {
 6828                                buffer_id: Some(buffer_id),
 6829                                excerpt_id,
 6830                                text_anchor: start,
 6831                                diff_base_anchor: None,
 6832                            }..Anchor {
 6833                                buffer_id: Some(buffer_id),
 6834                                excerpt_id,
 6835                                text_anchor: end,
 6836                                diff_base_anchor: None,
 6837                            };
 6838                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6839                                write_ranges.push(range);
 6840                            } else {
 6841                                read_ranges.push(range);
 6842                            }
 6843                        }
 6844                    }
 6845
 6846                    this.highlight_background::<DocumentHighlightRead>(
 6847                        &read_ranges,
 6848                        |theme| theme.colors().editor_document_highlight_read_background,
 6849                        cx,
 6850                    );
 6851                    this.highlight_background::<DocumentHighlightWrite>(
 6852                        &write_ranges,
 6853                        |theme| theme.colors().editor_document_highlight_write_background,
 6854                        cx,
 6855                    );
 6856                    cx.notify();
 6857                })
 6858                .log_err();
 6859            }
 6860        }));
 6861        None
 6862    }
 6863
 6864    fn prepare_highlight_query_from_selection(
 6865        &mut self,
 6866        cx: &mut Context<Editor>,
 6867    ) -> Option<(String, Range<Anchor>)> {
 6868        if matches!(self.mode, EditorMode::SingleLine) {
 6869            return None;
 6870        }
 6871        if !EditorSettings::get_global(cx).selection_highlight {
 6872            return None;
 6873        }
 6874        if self.selections.count() != 1 || self.selections.line_mode {
 6875            return None;
 6876        }
 6877        let selection = self.selections.newest::<Point>(cx);
 6878        if selection.is_empty() || selection.start.row != selection.end.row {
 6879            return None;
 6880        }
 6881        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6882        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6883        let query = multi_buffer_snapshot
 6884            .text_for_range(selection_anchor_range.clone())
 6885            .collect::<String>();
 6886        if query.trim().is_empty() {
 6887            return None;
 6888        }
 6889        Some((query, selection_anchor_range))
 6890    }
 6891
 6892    fn update_selection_occurrence_highlights(
 6893        &mut self,
 6894        query_text: String,
 6895        query_range: Range<Anchor>,
 6896        multi_buffer_range_to_query: Range<Point>,
 6897        use_debounce: bool,
 6898        window: &mut Window,
 6899        cx: &mut Context<Editor>,
 6900    ) -> Task<()> {
 6901        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6902        cx.spawn_in(window, async move |editor, cx| {
 6903            if use_debounce {
 6904                cx.background_executor()
 6905                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6906                    .await;
 6907            }
 6908            let match_task = cx.background_spawn(async move {
 6909                let buffer_ranges = multi_buffer_snapshot
 6910                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6911                    .into_iter()
 6912                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6913                let mut match_ranges = Vec::new();
 6914                let Ok(regex) = project::search::SearchQuery::text(
 6915                    query_text.clone(),
 6916                    false,
 6917                    false,
 6918                    false,
 6919                    Default::default(),
 6920                    Default::default(),
 6921                    false,
 6922                    None,
 6923                ) else {
 6924                    return Vec::default();
 6925                };
 6926                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6927                    match_ranges.extend(
 6928                        regex
 6929                            .search(buffer_snapshot, Some(search_range.clone()))
 6930                            .await
 6931                            .into_iter()
 6932                            .filter_map(|match_range| {
 6933                                let match_start = buffer_snapshot
 6934                                    .anchor_after(search_range.start + match_range.start);
 6935                                let match_end = buffer_snapshot
 6936                                    .anchor_before(search_range.start + match_range.end);
 6937                                let match_anchor_range = Anchor::range_in_buffer(
 6938                                    excerpt_id,
 6939                                    buffer_snapshot.remote_id(),
 6940                                    match_start..match_end,
 6941                                );
 6942                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6943                            }),
 6944                    );
 6945                }
 6946                match_ranges
 6947            });
 6948            let match_ranges = match_task.await;
 6949            editor
 6950                .update_in(cx, |editor, _, cx| {
 6951                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6952                    if !match_ranges.is_empty() {
 6953                        editor.highlight_background::<SelectedTextHighlight>(
 6954                            &match_ranges,
 6955                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6956                            cx,
 6957                        )
 6958                    }
 6959                })
 6960                .log_err();
 6961        })
 6962    }
 6963
 6964    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6965        struct NewlineFold;
 6966        let type_id = std::any::TypeId::of::<NewlineFold>();
 6967        if !self.mode.is_single_line() {
 6968            return;
 6969        }
 6970        let snapshot = self.snapshot(window, cx);
 6971        if snapshot.buffer_snapshot.max_point().row == 0 {
 6972            return;
 6973        }
 6974        let task = cx.background_spawn(async move {
 6975            let new_newlines = snapshot
 6976                .buffer_chars_at(0)
 6977                .filter_map(|(c, i)| {
 6978                    if c == '\n' {
 6979                        Some(
 6980                            snapshot.buffer_snapshot.anchor_after(i)
 6981                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6982                        )
 6983                    } else {
 6984                        None
 6985                    }
 6986                })
 6987                .collect::<Vec<_>>();
 6988            let existing_newlines = snapshot
 6989                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6990                .filter_map(|fold| {
 6991                    if fold.placeholder.type_tag == Some(type_id) {
 6992                        Some(fold.range.start..fold.range.end)
 6993                    } else {
 6994                        None
 6995                    }
 6996                })
 6997                .collect::<Vec<_>>();
 6998
 6999            (new_newlines, existing_newlines)
 7000        });
 7001        self.folding_newlines = cx.spawn(async move |this, cx| {
 7002            let (new_newlines, existing_newlines) = task.await;
 7003            if new_newlines == existing_newlines {
 7004                return;
 7005            }
 7006            let placeholder = FoldPlaceholder {
 7007                render: Arc::new(move |_, _, cx| {
 7008                    div()
 7009                        .bg(cx.theme().status().hint_background)
 7010                        .border_b_1()
 7011                        .size_full()
 7012                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7013                        .border_color(cx.theme().status().hint)
 7014                        .child("\\n")
 7015                        .into_any()
 7016                }),
 7017                constrain_width: false,
 7018                merge_adjacent: false,
 7019                type_tag: Some(type_id),
 7020            };
 7021            let creases = new_newlines
 7022                .into_iter()
 7023                .map(|range| Crease::simple(range, placeholder.clone()))
 7024                .collect();
 7025            this.update(cx, |this, cx| {
 7026                this.display_map.update(cx, |display_map, cx| {
 7027                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7028                    display_map.fold(creases, cx);
 7029                });
 7030            })
 7031            .ok();
 7032        });
 7033    }
 7034
 7035    fn refresh_selected_text_highlights(
 7036        &mut self,
 7037        on_buffer_edit: bool,
 7038        window: &mut Window,
 7039        cx: &mut Context<Editor>,
 7040    ) {
 7041        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7042        else {
 7043            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7044            self.quick_selection_highlight_task.take();
 7045            self.debounced_selection_highlight_task.take();
 7046            return;
 7047        };
 7048        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7049        if on_buffer_edit
 7050            || self
 7051                .quick_selection_highlight_task
 7052                .as_ref()
 7053                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7054        {
 7055            let multi_buffer_visible_start = self
 7056                .scroll_manager
 7057                .anchor()
 7058                .anchor
 7059                .to_point(&multi_buffer_snapshot);
 7060            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7061                multi_buffer_visible_start
 7062                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7063                Bias::Left,
 7064            );
 7065            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7066            self.quick_selection_highlight_task = Some((
 7067                query_range.clone(),
 7068                self.update_selection_occurrence_highlights(
 7069                    query_text.clone(),
 7070                    query_range.clone(),
 7071                    multi_buffer_visible_range,
 7072                    false,
 7073                    window,
 7074                    cx,
 7075                ),
 7076            ));
 7077        }
 7078        if on_buffer_edit
 7079            || self
 7080                .debounced_selection_highlight_task
 7081                .as_ref()
 7082                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7083        {
 7084            let multi_buffer_start = multi_buffer_snapshot
 7085                .anchor_before(0)
 7086                .to_point(&multi_buffer_snapshot);
 7087            let multi_buffer_end = multi_buffer_snapshot
 7088                .anchor_after(multi_buffer_snapshot.len())
 7089                .to_point(&multi_buffer_snapshot);
 7090            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7091            self.debounced_selection_highlight_task = Some((
 7092                query_range.clone(),
 7093                self.update_selection_occurrence_highlights(
 7094                    query_text,
 7095                    query_range,
 7096                    multi_buffer_full_range,
 7097                    true,
 7098                    window,
 7099                    cx,
 7100                ),
 7101            ));
 7102        }
 7103    }
 7104
 7105    pub fn refresh_edit_prediction(
 7106        &mut self,
 7107        debounce: bool,
 7108        user_requested: bool,
 7109        window: &mut Window,
 7110        cx: &mut Context<Self>,
 7111    ) -> Option<()> {
 7112        if DisableAiSettings::get_global(cx).disable_ai {
 7113            return None;
 7114        }
 7115
 7116        let provider = self.edit_prediction_provider()?;
 7117        let cursor = self.selections.newest_anchor().head();
 7118        let (buffer, cursor_buffer_position) =
 7119            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7120
 7121        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7122            self.discard_edit_prediction(false, cx);
 7123            return None;
 7124        }
 7125
 7126        if !user_requested
 7127            && (!self.should_show_edit_predictions()
 7128                || !self.is_focused(window)
 7129                || buffer.read(cx).is_empty())
 7130        {
 7131            self.discard_edit_prediction(false, cx);
 7132            return None;
 7133        }
 7134
 7135        self.update_visible_edit_prediction(window, cx);
 7136        provider.refresh(
 7137            self.project.clone(),
 7138            buffer,
 7139            cursor_buffer_position,
 7140            debounce,
 7141            cx,
 7142        );
 7143        Some(())
 7144    }
 7145
 7146    fn show_edit_predictions_in_menu(&self) -> bool {
 7147        match self.edit_prediction_settings {
 7148            EditPredictionSettings::Disabled => false,
 7149            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7150        }
 7151    }
 7152
 7153    pub fn edit_predictions_enabled(&self) -> bool {
 7154        match self.edit_prediction_settings {
 7155            EditPredictionSettings::Disabled => false,
 7156            EditPredictionSettings::Enabled { .. } => true,
 7157        }
 7158    }
 7159
 7160    fn edit_prediction_requires_modifier(&self) -> bool {
 7161        match self.edit_prediction_settings {
 7162            EditPredictionSettings::Disabled => false,
 7163            EditPredictionSettings::Enabled {
 7164                preview_requires_modifier,
 7165                ..
 7166            } => preview_requires_modifier,
 7167        }
 7168    }
 7169
 7170    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7171        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7172            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7173            self.discard_edit_prediction(false, cx);
 7174        } else {
 7175            let selection = self.selections.newest_anchor();
 7176            let cursor = selection.head();
 7177
 7178            if let Some((buffer, cursor_buffer_position)) =
 7179                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7180            {
 7181                self.edit_prediction_settings =
 7182                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7183            }
 7184        }
 7185    }
 7186
 7187    fn edit_prediction_settings_at_position(
 7188        &self,
 7189        buffer: &Entity<Buffer>,
 7190        buffer_position: language::Anchor,
 7191        cx: &App,
 7192    ) -> EditPredictionSettings {
 7193        if !self.mode.is_full()
 7194            || !self.show_edit_predictions_override.unwrap_or(true)
 7195            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7196        {
 7197            return EditPredictionSettings::Disabled;
 7198        }
 7199
 7200        let buffer = buffer.read(cx);
 7201
 7202        let file = buffer.file();
 7203
 7204        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7205            return EditPredictionSettings::Disabled;
 7206        };
 7207
 7208        let by_provider = matches!(
 7209            self.menu_edit_predictions_policy,
 7210            MenuEditPredictionsPolicy::ByProvider
 7211        );
 7212
 7213        let show_in_menu = by_provider
 7214            && self
 7215                .edit_prediction_provider
 7216                .as_ref()
 7217                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7218
 7219        let preview_requires_modifier =
 7220            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7221
 7222        EditPredictionSettings::Enabled {
 7223            show_in_menu,
 7224            preview_requires_modifier,
 7225        }
 7226    }
 7227
 7228    fn should_show_edit_predictions(&self) -> bool {
 7229        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7230    }
 7231
 7232    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7233        matches!(
 7234            self.edit_prediction_preview,
 7235            EditPredictionPreview::Active { .. }
 7236        )
 7237    }
 7238
 7239    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7240        let cursor = self.selections.newest_anchor().head();
 7241        if let Some((buffer, cursor_position)) =
 7242            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7243        {
 7244            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7245        } else {
 7246            false
 7247        }
 7248    }
 7249
 7250    pub fn supports_minimap(&self, cx: &App) -> bool {
 7251        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7252    }
 7253
 7254    fn edit_predictions_enabled_in_buffer(
 7255        &self,
 7256        buffer: &Entity<Buffer>,
 7257        buffer_position: language::Anchor,
 7258        cx: &App,
 7259    ) -> bool {
 7260        maybe!({
 7261            if self.read_only(cx) {
 7262                return Some(false);
 7263            }
 7264            let provider = self.edit_prediction_provider()?;
 7265            if !provider.is_enabled(buffer, buffer_position, cx) {
 7266                return Some(false);
 7267            }
 7268            let buffer = buffer.read(cx);
 7269            let Some(file) = buffer.file() else {
 7270                return Some(true);
 7271            };
 7272            let settings = all_language_settings(Some(file), cx);
 7273            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7274        })
 7275        .unwrap_or(false)
 7276    }
 7277
 7278    fn cycle_edit_prediction(
 7279        &mut self,
 7280        direction: Direction,
 7281        window: &mut Window,
 7282        cx: &mut Context<Self>,
 7283    ) -> Option<()> {
 7284        let provider = self.edit_prediction_provider()?;
 7285        let cursor = self.selections.newest_anchor().head();
 7286        let (buffer, cursor_buffer_position) =
 7287            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7288        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7289            return None;
 7290        }
 7291
 7292        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7293        self.update_visible_edit_prediction(window, cx);
 7294
 7295        Some(())
 7296    }
 7297
 7298    pub fn show_edit_prediction(
 7299        &mut self,
 7300        _: &ShowEditPrediction,
 7301        window: &mut Window,
 7302        cx: &mut Context<Self>,
 7303    ) {
 7304        if !self.has_active_edit_prediction() {
 7305            self.refresh_edit_prediction(false, true, window, cx);
 7306            return;
 7307        }
 7308
 7309        self.update_visible_edit_prediction(window, cx);
 7310    }
 7311
 7312    pub fn display_cursor_names(
 7313        &mut self,
 7314        _: &DisplayCursorNames,
 7315        window: &mut Window,
 7316        cx: &mut Context<Self>,
 7317    ) {
 7318        self.show_cursor_names(window, cx);
 7319    }
 7320
 7321    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7322        self.show_cursor_names = true;
 7323        cx.notify();
 7324        cx.spawn_in(window, async move |this, cx| {
 7325            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7326            this.update(cx, |this, cx| {
 7327                this.show_cursor_names = false;
 7328                cx.notify()
 7329            })
 7330            .ok()
 7331        })
 7332        .detach();
 7333    }
 7334
 7335    pub fn next_edit_prediction(
 7336        &mut self,
 7337        _: &NextEditPrediction,
 7338        window: &mut Window,
 7339        cx: &mut Context<Self>,
 7340    ) {
 7341        if self.has_active_edit_prediction() {
 7342            self.cycle_edit_prediction(Direction::Next, window, cx);
 7343        } else {
 7344            let is_copilot_disabled = self
 7345                .refresh_edit_prediction(false, true, window, cx)
 7346                .is_none();
 7347            if is_copilot_disabled {
 7348                cx.propagate();
 7349            }
 7350        }
 7351    }
 7352
 7353    pub fn previous_edit_prediction(
 7354        &mut self,
 7355        _: &PreviousEditPrediction,
 7356        window: &mut Window,
 7357        cx: &mut Context<Self>,
 7358    ) {
 7359        if self.has_active_edit_prediction() {
 7360            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7361        } else {
 7362            let is_copilot_disabled = self
 7363                .refresh_edit_prediction(false, true, window, cx)
 7364                .is_none();
 7365            if is_copilot_disabled {
 7366                cx.propagate();
 7367            }
 7368        }
 7369    }
 7370
 7371    pub fn accept_edit_prediction(
 7372        &mut self,
 7373        _: &AcceptEditPrediction,
 7374        window: &mut Window,
 7375        cx: &mut Context<Self>,
 7376    ) {
 7377        if self.show_edit_predictions_in_menu() {
 7378            self.hide_context_menu(window, cx);
 7379        }
 7380
 7381        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7382            return;
 7383        };
 7384
 7385        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7386
 7387        match &active_edit_prediction.completion {
 7388            EditPrediction::Move { target, .. } => {
 7389                let target = *target;
 7390
 7391                if let Some(position_map) = &self.last_position_map {
 7392                    if position_map
 7393                        .visible_row_range
 7394                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7395                        || !self.edit_prediction_requires_modifier()
 7396                    {
 7397                        self.unfold_ranges(&[target..target], true, false, cx);
 7398                        // Note that this is also done in vim's handler of the Tab action.
 7399                        self.change_selections(
 7400                            SelectionEffects::scroll(Autoscroll::newest()),
 7401                            window,
 7402                            cx,
 7403                            |selections| {
 7404                                selections.select_anchor_ranges([target..target]);
 7405                            },
 7406                        );
 7407                        self.clear_row_highlights::<EditPredictionPreview>();
 7408
 7409                        self.edit_prediction_preview
 7410                            .set_previous_scroll_position(None);
 7411                    } else {
 7412                        self.edit_prediction_preview
 7413                            .set_previous_scroll_position(Some(
 7414                                position_map.snapshot.scroll_anchor,
 7415                            ));
 7416
 7417                        self.highlight_rows::<EditPredictionPreview>(
 7418                            target..target,
 7419                            cx.theme().colors().editor_highlighted_line_background,
 7420                            RowHighlightOptions {
 7421                                autoscroll: true,
 7422                                ..Default::default()
 7423                            },
 7424                            cx,
 7425                        );
 7426                        self.request_autoscroll(Autoscroll::fit(), cx);
 7427                    }
 7428                }
 7429            }
 7430            EditPrediction::Edit { edits, .. } => {
 7431                if let Some(provider) = self.edit_prediction_provider() {
 7432                    provider.accept(cx);
 7433                }
 7434
 7435                // Store the transaction ID and selections before applying the edit
 7436                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7437
 7438                let snapshot = self.buffer.read(cx).snapshot(cx);
 7439                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7440
 7441                self.buffer.update(cx, |buffer, cx| {
 7442                    buffer.edit(edits.iter().cloned(), None, cx)
 7443                });
 7444
 7445                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7446                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7447                });
 7448
 7449                let selections = self.selections.disjoint_anchors();
 7450                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7451                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7452                    if has_new_transaction {
 7453                        self.selection_history
 7454                            .insert_transaction(transaction_id_now, selections);
 7455                    }
 7456                }
 7457
 7458                self.update_visible_edit_prediction(window, cx);
 7459                if self.active_edit_prediction.is_none() {
 7460                    self.refresh_edit_prediction(true, true, window, cx);
 7461                }
 7462
 7463                cx.notify();
 7464            }
 7465        }
 7466
 7467        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7468    }
 7469
 7470    pub fn accept_partial_edit_prediction(
 7471        &mut self,
 7472        _: &AcceptPartialEditPrediction,
 7473        window: &mut Window,
 7474        cx: &mut Context<Self>,
 7475    ) {
 7476        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7477            return;
 7478        };
 7479        if self.selections.count() != 1 {
 7480            return;
 7481        }
 7482
 7483        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7484
 7485        match &active_edit_prediction.completion {
 7486            EditPrediction::Move { target, .. } => {
 7487                let target = *target;
 7488                self.change_selections(
 7489                    SelectionEffects::scroll(Autoscroll::newest()),
 7490                    window,
 7491                    cx,
 7492                    |selections| {
 7493                        selections.select_anchor_ranges([target..target]);
 7494                    },
 7495                );
 7496            }
 7497            EditPrediction::Edit { edits, .. } => {
 7498                // Find an insertion that starts at the cursor position.
 7499                let snapshot = self.buffer.read(cx).snapshot(cx);
 7500                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7501                let insertion = edits.iter().find_map(|(range, text)| {
 7502                    let range = range.to_offset(&snapshot);
 7503                    if range.is_empty() && range.start == cursor_offset {
 7504                        Some(text)
 7505                    } else {
 7506                        None
 7507                    }
 7508                });
 7509
 7510                if let Some(text) = insertion {
 7511                    let mut partial_completion = text
 7512                        .chars()
 7513                        .by_ref()
 7514                        .take_while(|c| c.is_alphabetic())
 7515                        .collect::<String>();
 7516                    if partial_completion.is_empty() {
 7517                        partial_completion = text
 7518                            .chars()
 7519                            .by_ref()
 7520                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7521                            .collect::<String>();
 7522                    }
 7523
 7524                    cx.emit(EditorEvent::InputHandled {
 7525                        utf16_range_to_replace: None,
 7526                        text: partial_completion.clone().into(),
 7527                    });
 7528
 7529                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7530
 7531                    self.refresh_edit_prediction(true, true, window, cx);
 7532                    cx.notify();
 7533                } else {
 7534                    self.accept_edit_prediction(&Default::default(), window, cx);
 7535                }
 7536            }
 7537        }
 7538    }
 7539
 7540    fn discard_edit_prediction(
 7541        &mut self,
 7542        should_report_edit_prediction_event: bool,
 7543        cx: &mut Context<Self>,
 7544    ) -> bool {
 7545        if should_report_edit_prediction_event {
 7546            let completion_id = self
 7547                .active_edit_prediction
 7548                .as_ref()
 7549                .and_then(|active_completion| active_completion.completion_id.clone());
 7550
 7551            self.report_edit_prediction_event(completion_id, false, cx);
 7552        }
 7553
 7554        if let Some(provider) = self.edit_prediction_provider() {
 7555            provider.discard(cx);
 7556        }
 7557
 7558        self.take_active_edit_prediction(cx)
 7559    }
 7560
 7561    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7562        let Some(provider) = self.edit_prediction_provider() else {
 7563            return;
 7564        };
 7565
 7566        let Some((_, buffer, _)) = self
 7567            .buffer
 7568            .read(cx)
 7569            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7570        else {
 7571            return;
 7572        };
 7573
 7574        let extension = buffer
 7575            .read(cx)
 7576            .file()
 7577            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7578
 7579        let event_type = match accepted {
 7580            true => "Edit Prediction Accepted",
 7581            false => "Edit Prediction Discarded",
 7582        };
 7583        telemetry::event!(
 7584            event_type,
 7585            provider = provider.name(),
 7586            prediction_id = id,
 7587            suggestion_accepted = accepted,
 7588            file_extension = extension,
 7589        );
 7590    }
 7591
 7592    pub fn has_active_edit_prediction(&self) -> bool {
 7593        self.active_edit_prediction.is_some()
 7594    }
 7595
 7596    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7597        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7598            return false;
 7599        };
 7600
 7601        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7602        self.clear_highlights::<EditPredictionHighlight>(cx);
 7603        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7604        true
 7605    }
 7606
 7607    /// Returns true when we're displaying the edit prediction popover below the cursor
 7608    /// like we are not previewing and the LSP autocomplete menu is visible
 7609    /// or we are in `when_holding_modifier` mode.
 7610    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7611        if self.edit_prediction_preview_is_active()
 7612            || !self.show_edit_predictions_in_menu()
 7613            || !self.edit_predictions_enabled()
 7614        {
 7615            return false;
 7616        }
 7617
 7618        if self.has_visible_completions_menu() {
 7619            return true;
 7620        }
 7621
 7622        has_completion && self.edit_prediction_requires_modifier()
 7623    }
 7624
 7625    fn handle_modifiers_changed(
 7626        &mut self,
 7627        modifiers: Modifiers,
 7628        position_map: &PositionMap,
 7629        window: &mut Window,
 7630        cx: &mut Context<Self>,
 7631    ) {
 7632        if self.show_edit_predictions_in_menu() {
 7633            self.update_edit_prediction_preview(&modifiers, window, cx);
 7634        }
 7635
 7636        self.update_selection_mode(&modifiers, position_map, window, cx);
 7637
 7638        let mouse_position = window.mouse_position();
 7639        if !position_map.text_hitbox.is_hovered(window) {
 7640            return;
 7641        }
 7642
 7643        self.update_hovered_link(
 7644            position_map.point_for_position(mouse_position),
 7645            &position_map.snapshot,
 7646            modifiers,
 7647            window,
 7648            cx,
 7649        )
 7650    }
 7651
 7652    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7653        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7654        if invert {
 7655            match multi_cursor_setting {
 7656                MultiCursorModifier::Alt => modifiers.alt,
 7657                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7658            }
 7659        } else {
 7660            match multi_cursor_setting {
 7661                MultiCursorModifier::Alt => modifiers.secondary(),
 7662                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7663            }
 7664        }
 7665    }
 7666
 7667    fn columnar_selection_mode(
 7668        modifiers: &Modifiers,
 7669        cx: &mut Context<Self>,
 7670    ) -> Option<ColumnarMode> {
 7671        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7672            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7673                Some(ColumnarMode::FromMouse)
 7674            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7675                Some(ColumnarMode::FromSelection)
 7676            } else {
 7677                None
 7678            }
 7679        } else {
 7680            None
 7681        }
 7682    }
 7683
 7684    fn update_selection_mode(
 7685        &mut self,
 7686        modifiers: &Modifiers,
 7687        position_map: &PositionMap,
 7688        window: &mut Window,
 7689        cx: &mut Context<Self>,
 7690    ) {
 7691        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7692            return;
 7693        };
 7694        if self.selections.pending.is_none() {
 7695            return;
 7696        }
 7697
 7698        let mouse_position = window.mouse_position();
 7699        let point_for_position = position_map.point_for_position(mouse_position);
 7700        let position = point_for_position.previous_valid;
 7701
 7702        self.select(
 7703            SelectPhase::BeginColumnar {
 7704                position,
 7705                reset: false,
 7706                mode,
 7707                goal_column: point_for_position.exact_unclipped.column(),
 7708            },
 7709            window,
 7710            cx,
 7711        );
 7712    }
 7713
 7714    fn update_edit_prediction_preview(
 7715        &mut self,
 7716        modifiers: &Modifiers,
 7717        window: &mut Window,
 7718        cx: &mut Context<Self>,
 7719    ) {
 7720        let mut modifiers_held = false;
 7721        if let Some(accept_keystroke) = self
 7722            .accept_edit_prediction_keybind(false, window, cx)
 7723            .keystroke()
 7724        {
 7725            modifiers_held = modifiers_held
 7726                || (accept_keystroke.modifiers() == modifiers
 7727                    && accept_keystroke.modifiers().modified());
 7728        };
 7729        if let Some(accept_partial_keystroke) = self
 7730            .accept_edit_prediction_keybind(true, window, cx)
 7731            .keystroke()
 7732        {
 7733            modifiers_held = modifiers_held
 7734                || (accept_partial_keystroke.modifiers() == modifiers
 7735                    && accept_partial_keystroke.modifiers().modified());
 7736        }
 7737
 7738        if modifiers_held {
 7739            if matches!(
 7740                self.edit_prediction_preview,
 7741                EditPredictionPreview::Inactive { .. }
 7742            ) {
 7743                self.edit_prediction_preview = EditPredictionPreview::Active {
 7744                    previous_scroll_position: None,
 7745                    since: Instant::now(),
 7746                };
 7747
 7748                self.update_visible_edit_prediction(window, cx);
 7749                cx.notify();
 7750            }
 7751        } else if let EditPredictionPreview::Active {
 7752            previous_scroll_position,
 7753            since,
 7754        } = self.edit_prediction_preview
 7755        {
 7756            if let (Some(previous_scroll_position), Some(position_map)) =
 7757                (previous_scroll_position, self.last_position_map.as_ref())
 7758            {
 7759                self.set_scroll_position(
 7760                    previous_scroll_position
 7761                        .scroll_position(&position_map.snapshot.display_snapshot),
 7762                    window,
 7763                    cx,
 7764                );
 7765            }
 7766
 7767            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7768                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7769            };
 7770            self.clear_row_highlights::<EditPredictionPreview>();
 7771            self.update_visible_edit_prediction(window, cx);
 7772            cx.notify();
 7773        }
 7774    }
 7775
 7776    fn update_visible_edit_prediction(
 7777        &mut self,
 7778        _window: &mut Window,
 7779        cx: &mut Context<Self>,
 7780    ) -> Option<()> {
 7781        if DisableAiSettings::get_global(cx).disable_ai {
 7782            return None;
 7783        }
 7784
 7785        if self.ime_transaction.is_some() {
 7786            self.discard_edit_prediction(false, cx);
 7787            return None;
 7788        }
 7789
 7790        let selection = self.selections.newest_anchor();
 7791        let cursor = selection.head();
 7792        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7793        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7794        let excerpt_id = cursor.excerpt_id;
 7795
 7796        let show_in_menu = self.show_edit_predictions_in_menu();
 7797        let completions_menu_has_precedence = !show_in_menu
 7798            && (self.context_menu.borrow().is_some()
 7799                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7800
 7801        if completions_menu_has_precedence
 7802            || !offset_selection.is_empty()
 7803            || self
 7804                .active_edit_prediction
 7805                .as_ref()
 7806                .is_some_and(|completion| {
 7807                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7808                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7809                    !invalidation_range.contains(&offset_selection.head())
 7810                })
 7811        {
 7812            self.discard_edit_prediction(false, cx);
 7813            return None;
 7814        }
 7815
 7816        self.take_active_edit_prediction(cx);
 7817        let Some(provider) = self.edit_prediction_provider() else {
 7818            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7819            return None;
 7820        };
 7821
 7822        let (buffer, cursor_buffer_position) =
 7823            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7824
 7825        self.edit_prediction_settings =
 7826            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7827
 7828        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7829            self.discard_edit_prediction(false, cx);
 7830            return None;
 7831        };
 7832
 7833        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7834
 7835        if self.edit_prediction_indent_conflict {
 7836            let cursor_point = cursor.to_point(&multibuffer);
 7837
 7838            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7839
 7840            if let Some((_, indent)) = indents.iter().next()
 7841                && indent.len == cursor_point.column
 7842            {
 7843                self.edit_prediction_indent_conflict = false;
 7844            }
 7845        }
 7846
 7847        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7848        let edits = edit_prediction
 7849            .edits
 7850            .into_iter()
 7851            .flat_map(|(range, new_text)| {
 7852                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7853                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7854                Some((start..end, new_text))
 7855            })
 7856            .collect::<Vec<_>>();
 7857        if edits.is_empty() {
 7858            return None;
 7859        }
 7860
 7861        let first_edit_start = edits.first().unwrap().0.start;
 7862        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7863        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7864
 7865        let last_edit_end = edits.last().unwrap().0.end;
 7866        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7867        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7868
 7869        let cursor_row = cursor.to_point(&multibuffer).row;
 7870
 7871        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7872
 7873        let mut inlay_ids = Vec::new();
 7874        let invalidation_row_range;
 7875        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7876            Some(cursor_row..edit_end_row)
 7877        } else if cursor_row > edit_end_row {
 7878            Some(edit_start_row..cursor_row)
 7879        } else {
 7880            None
 7881        };
 7882        let supports_jump = self
 7883            .edit_prediction_provider
 7884            .as_ref()
 7885            .map(|provider| provider.provider.supports_jump_to_edit())
 7886            .unwrap_or(true);
 7887
 7888        let is_move = supports_jump
 7889            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7890        let completion = if is_move {
 7891            invalidation_row_range =
 7892                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7893            let target = first_edit_start;
 7894            EditPrediction::Move { target, snapshot }
 7895        } else {
 7896            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7897                && !self.edit_predictions_hidden_for_vim_mode;
 7898
 7899            if show_completions_in_buffer {
 7900                if edits
 7901                    .iter()
 7902                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7903                {
 7904                    let mut inlays = Vec::new();
 7905                    for (range, new_text) in &edits {
 7906                        let inlay = Inlay::edit_prediction(
 7907                            post_inc(&mut self.next_inlay_id),
 7908                            range.start,
 7909                            new_text.as_str(),
 7910                        );
 7911                        inlay_ids.push(inlay.id);
 7912                        inlays.push(inlay);
 7913                    }
 7914
 7915                    self.splice_inlays(&[], inlays, cx);
 7916                } else {
 7917                    let background_color = cx.theme().status().deleted_background;
 7918                    self.highlight_text::<EditPredictionHighlight>(
 7919                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7920                        HighlightStyle {
 7921                            background_color: Some(background_color),
 7922                            ..Default::default()
 7923                        },
 7924                        cx,
 7925                    );
 7926                }
 7927            }
 7928
 7929            invalidation_row_range = edit_start_row..edit_end_row;
 7930
 7931            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7932                if provider.show_tab_accept_marker() {
 7933                    EditDisplayMode::TabAccept
 7934                } else {
 7935                    EditDisplayMode::Inline
 7936                }
 7937            } else {
 7938                EditDisplayMode::DiffPopover
 7939            };
 7940
 7941            EditPrediction::Edit {
 7942                edits,
 7943                edit_preview: edit_prediction.edit_preview,
 7944                display_mode,
 7945                snapshot,
 7946            }
 7947        };
 7948
 7949        let invalidation_range = multibuffer
 7950            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7951            ..multibuffer.anchor_after(Point::new(
 7952                invalidation_row_range.end,
 7953                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7954            ));
 7955
 7956        self.stale_edit_prediction_in_menu = None;
 7957        self.active_edit_prediction = Some(EditPredictionState {
 7958            inlay_ids,
 7959            completion,
 7960            completion_id: edit_prediction.id,
 7961            invalidation_range,
 7962        });
 7963
 7964        cx.notify();
 7965
 7966        Some(())
 7967    }
 7968
 7969    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7970        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7971    }
 7972
 7973    fn clear_tasks(&mut self) {
 7974        self.tasks.clear()
 7975    }
 7976
 7977    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7978        if self.tasks.insert(key, value).is_some() {
 7979            // This case should hopefully be rare, but just in case...
 7980            log::error!(
 7981                "multiple different run targets found on a single line, only the last target will be rendered"
 7982            )
 7983        }
 7984    }
 7985
 7986    /// Get all display points of breakpoints that will be rendered within editor
 7987    ///
 7988    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7989    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7990    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7991    fn active_breakpoints(
 7992        &self,
 7993        range: Range<DisplayRow>,
 7994        window: &mut Window,
 7995        cx: &mut Context<Self>,
 7996    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7997        let mut breakpoint_display_points = HashMap::default();
 7998
 7999        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8000            return breakpoint_display_points;
 8001        };
 8002
 8003        let snapshot = self.snapshot(window, cx);
 8004
 8005        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8006        let Some(project) = self.project() else {
 8007            return breakpoint_display_points;
 8008        };
 8009
 8010        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8011            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8012
 8013        for (buffer_snapshot, range, excerpt_id) in
 8014            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8015        {
 8016            let Some(buffer) = project
 8017                .read(cx)
 8018                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8019            else {
 8020                continue;
 8021            };
 8022            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8023                &buffer,
 8024                Some(
 8025                    buffer_snapshot.anchor_before(range.start)
 8026                        ..buffer_snapshot.anchor_after(range.end),
 8027                ),
 8028                buffer_snapshot,
 8029                cx,
 8030            );
 8031            for (breakpoint, state) in breakpoints {
 8032                let multi_buffer_anchor =
 8033                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8034                let position = multi_buffer_anchor
 8035                    .to_point(multi_buffer_snapshot)
 8036                    .to_display_point(&snapshot);
 8037
 8038                breakpoint_display_points.insert(
 8039                    position.row(),
 8040                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8041                );
 8042            }
 8043        }
 8044
 8045        breakpoint_display_points
 8046    }
 8047
 8048    fn breakpoint_context_menu(
 8049        &self,
 8050        anchor: Anchor,
 8051        window: &mut Window,
 8052        cx: &mut Context<Self>,
 8053    ) -> Entity<ui::ContextMenu> {
 8054        let weak_editor = cx.weak_entity();
 8055        let focus_handle = self.focus_handle(cx);
 8056
 8057        let row = self
 8058            .buffer
 8059            .read(cx)
 8060            .snapshot(cx)
 8061            .summary_for_anchor::<Point>(&anchor)
 8062            .row;
 8063
 8064        let breakpoint = self
 8065            .breakpoint_at_row(row, window, cx)
 8066            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8067
 8068        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8069            "Edit Log Breakpoint"
 8070        } else {
 8071            "Set Log Breakpoint"
 8072        };
 8073
 8074        let condition_breakpoint_msg = if breakpoint
 8075            .as_ref()
 8076            .is_some_and(|bp| bp.1.condition.is_some())
 8077        {
 8078            "Edit Condition Breakpoint"
 8079        } else {
 8080            "Set Condition Breakpoint"
 8081        };
 8082
 8083        let hit_condition_breakpoint_msg = if breakpoint
 8084            .as_ref()
 8085            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8086        {
 8087            "Edit Hit Condition Breakpoint"
 8088        } else {
 8089            "Set Hit Condition Breakpoint"
 8090        };
 8091
 8092        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8093            "Unset Breakpoint"
 8094        } else {
 8095            "Set Breakpoint"
 8096        };
 8097
 8098        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8099
 8100        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8101            BreakpointState::Enabled => Some("Disable"),
 8102            BreakpointState::Disabled => Some("Enable"),
 8103        });
 8104
 8105        let (anchor, breakpoint) =
 8106            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8107
 8108        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8109            menu.on_blur_subscription(Subscription::new(|| {}))
 8110                .context(focus_handle)
 8111                .when(run_to_cursor, |this| {
 8112                    let weak_editor = weak_editor.clone();
 8113                    this.entry("Run to cursor", None, move |window, cx| {
 8114                        weak_editor
 8115                            .update(cx, |editor, cx| {
 8116                                editor.change_selections(
 8117                                    SelectionEffects::no_scroll(),
 8118                                    window,
 8119                                    cx,
 8120                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8121                                );
 8122                            })
 8123                            .ok();
 8124
 8125                        window.dispatch_action(Box::new(RunToCursor), cx);
 8126                    })
 8127                    .separator()
 8128                })
 8129                .when_some(toggle_state_msg, |this, msg| {
 8130                    this.entry(msg, None, {
 8131                        let weak_editor = weak_editor.clone();
 8132                        let breakpoint = breakpoint.clone();
 8133                        move |_window, cx| {
 8134                            weak_editor
 8135                                .update(cx, |this, cx| {
 8136                                    this.edit_breakpoint_at_anchor(
 8137                                        anchor,
 8138                                        breakpoint.as_ref().clone(),
 8139                                        BreakpointEditAction::InvertState,
 8140                                        cx,
 8141                                    );
 8142                                })
 8143                                .log_err();
 8144                        }
 8145                    })
 8146                })
 8147                .entry(set_breakpoint_msg, None, {
 8148                    let weak_editor = weak_editor.clone();
 8149                    let breakpoint = breakpoint.clone();
 8150                    move |_window, cx| {
 8151                        weak_editor
 8152                            .update(cx, |this, cx| {
 8153                                this.edit_breakpoint_at_anchor(
 8154                                    anchor,
 8155                                    breakpoint.as_ref().clone(),
 8156                                    BreakpointEditAction::Toggle,
 8157                                    cx,
 8158                                );
 8159                            })
 8160                            .log_err();
 8161                    }
 8162                })
 8163                .entry(log_breakpoint_msg, None, {
 8164                    let breakpoint = breakpoint.clone();
 8165                    let weak_editor = weak_editor.clone();
 8166                    move |window, cx| {
 8167                        weak_editor
 8168                            .update(cx, |this, cx| {
 8169                                this.add_edit_breakpoint_block(
 8170                                    anchor,
 8171                                    breakpoint.as_ref(),
 8172                                    BreakpointPromptEditAction::Log,
 8173                                    window,
 8174                                    cx,
 8175                                );
 8176                            })
 8177                            .log_err();
 8178                    }
 8179                })
 8180                .entry(condition_breakpoint_msg, None, {
 8181                    let breakpoint = breakpoint.clone();
 8182                    let weak_editor = weak_editor.clone();
 8183                    move |window, cx| {
 8184                        weak_editor
 8185                            .update(cx, |this, cx| {
 8186                                this.add_edit_breakpoint_block(
 8187                                    anchor,
 8188                                    breakpoint.as_ref(),
 8189                                    BreakpointPromptEditAction::Condition,
 8190                                    window,
 8191                                    cx,
 8192                                );
 8193                            })
 8194                            .log_err();
 8195                    }
 8196                })
 8197                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8198                    weak_editor
 8199                        .update(cx, |this, cx| {
 8200                            this.add_edit_breakpoint_block(
 8201                                anchor,
 8202                                breakpoint.as_ref(),
 8203                                BreakpointPromptEditAction::HitCondition,
 8204                                window,
 8205                                cx,
 8206                            );
 8207                        })
 8208                        .log_err();
 8209                })
 8210        })
 8211    }
 8212
 8213    fn render_breakpoint(
 8214        &self,
 8215        position: Anchor,
 8216        row: DisplayRow,
 8217        breakpoint: &Breakpoint,
 8218        state: Option<BreakpointSessionState>,
 8219        cx: &mut Context<Self>,
 8220    ) -> IconButton {
 8221        let is_rejected = state.is_some_and(|s| !s.verified);
 8222        // Is it a breakpoint that shows up when hovering over gutter?
 8223        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8224            (false, false),
 8225            |PhantomBreakpointIndicator {
 8226                 is_active,
 8227                 display_row,
 8228                 collides_with_existing_breakpoint,
 8229             }| {
 8230                (
 8231                    is_active && display_row == row,
 8232                    collides_with_existing_breakpoint,
 8233                )
 8234            },
 8235        );
 8236
 8237        let (color, icon) = {
 8238            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8239                (false, false) => ui::IconName::DebugBreakpoint,
 8240                (true, false) => ui::IconName::DebugLogBreakpoint,
 8241                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8242                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8243            };
 8244
 8245            let color = if is_phantom {
 8246                Color::Hint
 8247            } else if is_rejected {
 8248                Color::Disabled
 8249            } else {
 8250                Color::Debugger
 8251            };
 8252
 8253            (color, icon)
 8254        };
 8255
 8256        let breakpoint = Arc::from(breakpoint.clone());
 8257
 8258        let alt_as_text = gpui::Keystroke {
 8259            modifiers: Modifiers::secondary_key(),
 8260            ..Default::default()
 8261        };
 8262        let primary_action_text = if breakpoint.is_disabled() {
 8263            "Enable breakpoint"
 8264        } else if is_phantom && !collides_with_existing {
 8265            "Set breakpoint"
 8266        } else {
 8267            "Unset breakpoint"
 8268        };
 8269        let focus_handle = self.focus_handle.clone();
 8270
 8271        let meta = if is_rejected {
 8272            SharedString::from("No executable code is associated with this line.")
 8273        } else if collides_with_existing && !breakpoint.is_disabled() {
 8274            SharedString::from(format!(
 8275                "{alt_as_text}-click to disable,\nright-click for more options."
 8276            ))
 8277        } else {
 8278            SharedString::from("Right-click for more options.")
 8279        };
 8280        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8281            .icon_size(IconSize::XSmall)
 8282            .size(ui::ButtonSize::None)
 8283            .when(is_rejected, |this| {
 8284                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8285            })
 8286            .icon_color(color)
 8287            .style(ButtonStyle::Transparent)
 8288            .on_click(cx.listener({
 8289                move |editor, event: &ClickEvent, window, cx| {
 8290                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8291                        BreakpointEditAction::InvertState
 8292                    } else {
 8293                        BreakpointEditAction::Toggle
 8294                    };
 8295
 8296                    window.focus(&editor.focus_handle(cx));
 8297                    editor.edit_breakpoint_at_anchor(
 8298                        position,
 8299                        breakpoint.as_ref().clone(),
 8300                        edit_action,
 8301                        cx,
 8302                    );
 8303                }
 8304            }))
 8305            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8306                editor.set_breakpoint_context_menu(
 8307                    row,
 8308                    Some(position),
 8309                    event.position(),
 8310                    window,
 8311                    cx,
 8312                );
 8313            }))
 8314            .tooltip(move |window, cx| {
 8315                Tooltip::with_meta_in(
 8316                    primary_action_text,
 8317                    Some(&ToggleBreakpoint),
 8318                    meta.clone(),
 8319                    &focus_handle,
 8320                    window,
 8321                    cx,
 8322                )
 8323            })
 8324    }
 8325
 8326    fn build_tasks_context(
 8327        project: &Entity<Project>,
 8328        buffer: &Entity<Buffer>,
 8329        buffer_row: u32,
 8330        tasks: &Arc<RunnableTasks>,
 8331        cx: &mut Context<Self>,
 8332    ) -> Task<Option<task::TaskContext>> {
 8333        let position = Point::new(buffer_row, tasks.column);
 8334        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8335        let location = Location {
 8336            buffer: buffer.clone(),
 8337            range: range_start..range_start,
 8338        };
 8339        // Fill in the environmental variables from the tree-sitter captures
 8340        let mut captured_task_variables = TaskVariables::default();
 8341        for (capture_name, value) in tasks.extra_variables.clone() {
 8342            captured_task_variables.insert(
 8343                task::VariableName::Custom(capture_name.into()),
 8344                value.clone(),
 8345            );
 8346        }
 8347        project.update(cx, |project, cx| {
 8348            project.task_store().update(cx, |task_store, cx| {
 8349                task_store.task_context_for_location(captured_task_variables, location, cx)
 8350            })
 8351        })
 8352    }
 8353
 8354    pub fn spawn_nearest_task(
 8355        &mut self,
 8356        action: &SpawnNearestTask,
 8357        window: &mut Window,
 8358        cx: &mut Context<Self>,
 8359    ) {
 8360        let Some((workspace, _)) = self.workspace.clone() else {
 8361            return;
 8362        };
 8363        let Some(project) = self.project.clone() else {
 8364            return;
 8365        };
 8366
 8367        // Try to find a closest, enclosing node using tree-sitter that has a task
 8368        let Some((buffer, buffer_row, tasks)) = self
 8369            .find_enclosing_node_task(cx)
 8370            // Or find the task that's closest in row-distance.
 8371            .or_else(|| self.find_closest_task(cx))
 8372        else {
 8373            return;
 8374        };
 8375
 8376        let reveal_strategy = action.reveal;
 8377        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8378        cx.spawn_in(window, async move |_, cx| {
 8379            let context = task_context.await?;
 8380            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8381
 8382            let resolved = &mut resolved_task.resolved;
 8383            resolved.reveal = reveal_strategy;
 8384
 8385            workspace
 8386                .update_in(cx, |workspace, window, cx| {
 8387                    workspace.schedule_resolved_task(
 8388                        task_source_kind,
 8389                        resolved_task,
 8390                        false,
 8391                        window,
 8392                        cx,
 8393                    );
 8394                })
 8395                .ok()
 8396        })
 8397        .detach();
 8398    }
 8399
 8400    fn find_closest_task(
 8401        &mut self,
 8402        cx: &mut Context<Self>,
 8403    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8404        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8405
 8406        let ((buffer_id, row), tasks) = self
 8407            .tasks
 8408            .iter()
 8409            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8410
 8411        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8412        let tasks = Arc::new(tasks.to_owned());
 8413        Some((buffer, *row, tasks))
 8414    }
 8415
 8416    fn find_enclosing_node_task(
 8417        &mut self,
 8418        cx: &mut Context<Self>,
 8419    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8420        let snapshot = self.buffer.read(cx).snapshot(cx);
 8421        let offset = self.selections.newest::<usize>(cx).head();
 8422        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8423        let buffer_id = excerpt.buffer().remote_id();
 8424
 8425        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8426        let mut cursor = layer.node().walk();
 8427
 8428        while cursor.goto_first_child_for_byte(offset).is_some() {
 8429            if cursor.node().end_byte() == offset {
 8430                cursor.goto_next_sibling();
 8431            }
 8432        }
 8433
 8434        // Ascend to the smallest ancestor that contains the range and has a task.
 8435        loop {
 8436            let node = cursor.node();
 8437            let node_range = node.byte_range();
 8438            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8439
 8440            // Check if this node contains our offset
 8441            if node_range.start <= offset && node_range.end >= offset {
 8442                // If it contains offset, check for task
 8443                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8444                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8445                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8446                }
 8447            }
 8448
 8449            if !cursor.goto_parent() {
 8450                break;
 8451            }
 8452        }
 8453        None
 8454    }
 8455
 8456    fn render_run_indicator(
 8457        &self,
 8458        _style: &EditorStyle,
 8459        is_active: bool,
 8460        row: DisplayRow,
 8461        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8462        cx: &mut Context<Self>,
 8463    ) -> IconButton {
 8464        let color = Color::Muted;
 8465        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8466
 8467        IconButton::new(
 8468            ("run_indicator", row.0 as usize),
 8469            ui::IconName::PlayOutlined,
 8470        )
 8471        .shape(ui::IconButtonShape::Square)
 8472        .icon_size(IconSize::XSmall)
 8473        .icon_color(color)
 8474        .toggle_state(is_active)
 8475        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8476            let quick_launch = match e {
 8477                ClickEvent::Keyboard(_) => true,
 8478                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8479            };
 8480
 8481            window.focus(&editor.focus_handle(cx));
 8482            editor.toggle_code_actions(
 8483                &ToggleCodeActions {
 8484                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8485                    quick_launch,
 8486                },
 8487                window,
 8488                cx,
 8489            );
 8490        }))
 8491        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8492            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8493        }))
 8494    }
 8495
 8496    pub fn context_menu_visible(&self) -> bool {
 8497        !self.edit_prediction_preview_is_active()
 8498            && self
 8499                .context_menu
 8500                .borrow()
 8501                .as_ref()
 8502                .is_some_and(|menu| menu.visible())
 8503    }
 8504
 8505    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8506        self.context_menu
 8507            .borrow()
 8508            .as_ref()
 8509            .map(|menu| menu.origin())
 8510    }
 8511
 8512    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8513        self.context_menu_options = Some(options);
 8514    }
 8515
 8516    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8517    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8518
 8519    fn render_edit_prediction_popover(
 8520        &mut self,
 8521        text_bounds: &Bounds<Pixels>,
 8522        content_origin: gpui::Point<Pixels>,
 8523        right_margin: Pixels,
 8524        editor_snapshot: &EditorSnapshot,
 8525        visible_row_range: Range<DisplayRow>,
 8526        scroll_top: f32,
 8527        scroll_bottom: f32,
 8528        line_layouts: &[LineWithInvisibles],
 8529        line_height: Pixels,
 8530        scroll_pixel_position: gpui::Point<Pixels>,
 8531        newest_selection_head: Option<DisplayPoint>,
 8532        editor_width: Pixels,
 8533        style: &EditorStyle,
 8534        window: &mut Window,
 8535        cx: &mut App,
 8536    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8537        if self.mode().is_minimap() {
 8538            return None;
 8539        }
 8540        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8541
 8542        if self.edit_prediction_visible_in_cursor_popover(true) {
 8543            return None;
 8544        }
 8545
 8546        match &active_edit_prediction.completion {
 8547            EditPrediction::Move { target, .. } => {
 8548                let target_display_point = target.to_display_point(editor_snapshot);
 8549
 8550                if self.edit_prediction_requires_modifier() {
 8551                    if !self.edit_prediction_preview_is_active() {
 8552                        return None;
 8553                    }
 8554
 8555                    self.render_edit_prediction_modifier_jump_popover(
 8556                        text_bounds,
 8557                        content_origin,
 8558                        visible_row_range,
 8559                        line_layouts,
 8560                        line_height,
 8561                        scroll_pixel_position,
 8562                        newest_selection_head,
 8563                        target_display_point,
 8564                        window,
 8565                        cx,
 8566                    )
 8567                } else {
 8568                    self.render_edit_prediction_eager_jump_popover(
 8569                        text_bounds,
 8570                        content_origin,
 8571                        editor_snapshot,
 8572                        visible_row_range,
 8573                        scroll_top,
 8574                        scroll_bottom,
 8575                        line_height,
 8576                        scroll_pixel_position,
 8577                        target_display_point,
 8578                        editor_width,
 8579                        window,
 8580                        cx,
 8581                    )
 8582                }
 8583            }
 8584            EditPrediction::Edit {
 8585                display_mode: EditDisplayMode::Inline,
 8586                ..
 8587            } => None,
 8588            EditPrediction::Edit {
 8589                display_mode: EditDisplayMode::TabAccept,
 8590                edits,
 8591                ..
 8592            } => {
 8593                let range = &edits.first()?.0;
 8594                let target_display_point = range.end.to_display_point(editor_snapshot);
 8595
 8596                self.render_edit_prediction_end_of_line_popover(
 8597                    "Accept",
 8598                    editor_snapshot,
 8599                    visible_row_range,
 8600                    target_display_point,
 8601                    line_height,
 8602                    scroll_pixel_position,
 8603                    content_origin,
 8604                    editor_width,
 8605                    window,
 8606                    cx,
 8607                )
 8608            }
 8609            EditPrediction::Edit {
 8610                edits,
 8611                edit_preview,
 8612                display_mode: EditDisplayMode::DiffPopover,
 8613                snapshot,
 8614            } => self.render_edit_prediction_diff_popover(
 8615                text_bounds,
 8616                content_origin,
 8617                right_margin,
 8618                editor_snapshot,
 8619                visible_row_range,
 8620                line_layouts,
 8621                line_height,
 8622                scroll_pixel_position,
 8623                newest_selection_head,
 8624                editor_width,
 8625                style,
 8626                edits,
 8627                edit_preview,
 8628                snapshot,
 8629                window,
 8630                cx,
 8631            ),
 8632        }
 8633    }
 8634
 8635    fn render_edit_prediction_modifier_jump_popover(
 8636        &mut self,
 8637        text_bounds: &Bounds<Pixels>,
 8638        content_origin: gpui::Point<Pixels>,
 8639        visible_row_range: Range<DisplayRow>,
 8640        line_layouts: &[LineWithInvisibles],
 8641        line_height: Pixels,
 8642        scroll_pixel_position: gpui::Point<Pixels>,
 8643        newest_selection_head: Option<DisplayPoint>,
 8644        target_display_point: DisplayPoint,
 8645        window: &mut Window,
 8646        cx: &mut App,
 8647    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8648        let scrolled_content_origin =
 8649            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8650
 8651        const SCROLL_PADDING_Y: Pixels = px(12.);
 8652
 8653        if target_display_point.row() < visible_row_range.start {
 8654            return self.render_edit_prediction_scroll_popover(
 8655                |_| SCROLL_PADDING_Y,
 8656                IconName::ArrowUp,
 8657                visible_row_range,
 8658                line_layouts,
 8659                newest_selection_head,
 8660                scrolled_content_origin,
 8661                window,
 8662                cx,
 8663            );
 8664        } else if target_display_point.row() >= visible_row_range.end {
 8665            return self.render_edit_prediction_scroll_popover(
 8666                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8667                IconName::ArrowDown,
 8668                visible_row_range,
 8669                line_layouts,
 8670                newest_selection_head,
 8671                scrolled_content_origin,
 8672                window,
 8673                cx,
 8674            );
 8675        }
 8676
 8677        const POLE_WIDTH: Pixels = px(2.);
 8678
 8679        let line_layout =
 8680            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8681        let target_column = target_display_point.column() as usize;
 8682
 8683        let target_x = line_layout.x_for_index(target_column);
 8684        let target_y =
 8685            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8686
 8687        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8688
 8689        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8690        border_color.l += 0.001;
 8691
 8692        let mut element = v_flex()
 8693            .items_end()
 8694            .when(flag_on_right, |el| el.items_start())
 8695            .child(if flag_on_right {
 8696                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8697                    .rounded_bl(px(0.))
 8698                    .rounded_tl(px(0.))
 8699                    .border_l_2()
 8700                    .border_color(border_color)
 8701            } else {
 8702                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8703                    .rounded_br(px(0.))
 8704                    .rounded_tr(px(0.))
 8705                    .border_r_2()
 8706                    .border_color(border_color)
 8707            })
 8708            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8709            .into_any();
 8710
 8711        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8712
 8713        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8714            - point(
 8715                if flag_on_right {
 8716                    POLE_WIDTH
 8717                } else {
 8718                    size.width - POLE_WIDTH
 8719                },
 8720                size.height - line_height,
 8721            );
 8722
 8723        origin.x = origin.x.max(content_origin.x);
 8724
 8725        element.prepaint_at(origin, window, cx);
 8726
 8727        Some((element, origin))
 8728    }
 8729
 8730    fn render_edit_prediction_scroll_popover(
 8731        &mut self,
 8732        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8733        scroll_icon: IconName,
 8734        visible_row_range: Range<DisplayRow>,
 8735        line_layouts: &[LineWithInvisibles],
 8736        newest_selection_head: Option<DisplayPoint>,
 8737        scrolled_content_origin: gpui::Point<Pixels>,
 8738        window: &mut Window,
 8739        cx: &mut App,
 8740    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8741        let mut element = self
 8742            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8743            .into_any();
 8744
 8745        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8746
 8747        let cursor = newest_selection_head?;
 8748        let cursor_row_layout =
 8749            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8750        let cursor_column = cursor.column() as usize;
 8751
 8752        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8753
 8754        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8755
 8756        element.prepaint_at(origin, window, cx);
 8757        Some((element, origin))
 8758    }
 8759
 8760    fn render_edit_prediction_eager_jump_popover(
 8761        &mut self,
 8762        text_bounds: &Bounds<Pixels>,
 8763        content_origin: gpui::Point<Pixels>,
 8764        editor_snapshot: &EditorSnapshot,
 8765        visible_row_range: Range<DisplayRow>,
 8766        scroll_top: f32,
 8767        scroll_bottom: f32,
 8768        line_height: Pixels,
 8769        scroll_pixel_position: gpui::Point<Pixels>,
 8770        target_display_point: DisplayPoint,
 8771        editor_width: Pixels,
 8772        window: &mut Window,
 8773        cx: &mut App,
 8774    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8775        if target_display_point.row().as_f32() < scroll_top {
 8776            let mut element = self
 8777                .render_edit_prediction_line_popover(
 8778                    "Jump to Edit",
 8779                    Some(IconName::ArrowUp),
 8780                    window,
 8781                    cx,
 8782                )?
 8783                .into_any();
 8784
 8785            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8786            let offset = point(
 8787                (text_bounds.size.width - size.width) / 2.,
 8788                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8789            );
 8790
 8791            let origin = text_bounds.origin + offset;
 8792            element.prepaint_at(origin, window, cx);
 8793            Some((element, origin))
 8794        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8795            let mut element = self
 8796                .render_edit_prediction_line_popover(
 8797                    "Jump to Edit",
 8798                    Some(IconName::ArrowDown),
 8799                    window,
 8800                    cx,
 8801                )?
 8802                .into_any();
 8803
 8804            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8805            let offset = point(
 8806                (text_bounds.size.width - size.width) / 2.,
 8807                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8808            );
 8809
 8810            let origin = text_bounds.origin + offset;
 8811            element.prepaint_at(origin, window, cx);
 8812            Some((element, origin))
 8813        } else {
 8814            self.render_edit_prediction_end_of_line_popover(
 8815                "Jump to Edit",
 8816                editor_snapshot,
 8817                visible_row_range,
 8818                target_display_point,
 8819                line_height,
 8820                scroll_pixel_position,
 8821                content_origin,
 8822                editor_width,
 8823                window,
 8824                cx,
 8825            )
 8826        }
 8827    }
 8828
 8829    fn render_edit_prediction_end_of_line_popover(
 8830        self: &mut Editor,
 8831        label: &'static str,
 8832        editor_snapshot: &EditorSnapshot,
 8833        visible_row_range: Range<DisplayRow>,
 8834        target_display_point: DisplayPoint,
 8835        line_height: Pixels,
 8836        scroll_pixel_position: gpui::Point<Pixels>,
 8837        content_origin: gpui::Point<Pixels>,
 8838        editor_width: Pixels,
 8839        window: &mut Window,
 8840        cx: &mut App,
 8841    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8842        let target_line_end = DisplayPoint::new(
 8843            target_display_point.row(),
 8844            editor_snapshot.line_len(target_display_point.row()),
 8845        );
 8846
 8847        let mut element = self
 8848            .render_edit_prediction_line_popover(label, None, window, cx)?
 8849            .into_any();
 8850
 8851        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8852
 8853        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8854
 8855        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8856        let mut origin = start_point
 8857            + line_origin
 8858            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8859        origin.x = origin.x.max(content_origin.x);
 8860
 8861        let max_x = content_origin.x + editor_width - size.width;
 8862
 8863        if origin.x > max_x {
 8864            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8865
 8866            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8867                origin.y += offset;
 8868                IconName::ArrowUp
 8869            } else {
 8870                origin.y -= offset;
 8871                IconName::ArrowDown
 8872            };
 8873
 8874            element = self
 8875                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8876                .into_any();
 8877
 8878            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8879
 8880            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8881        }
 8882
 8883        element.prepaint_at(origin, window, cx);
 8884        Some((element, origin))
 8885    }
 8886
 8887    fn render_edit_prediction_diff_popover(
 8888        self: &Editor,
 8889        text_bounds: &Bounds<Pixels>,
 8890        content_origin: gpui::Point<Pixels>,
 8891        right_margin: Pixels,
 8892        editor_snapshot: &EditorSnapshot,
 8893        visible_row_range: Range<DisplayRow>,
 8894        line_layouts: &[LineWithInvisibles],
 8895        line_height: Pixels,
 8896        scroll_pixel_position: gpui::Point<Pixels>,
 8897        newest_selection_head: Option<DisplayPoint>,
 8898        editor_width: Pixels,
 8899        style: &EditorStyle,
 8900        edits: &Vec<(Range<Anchor>, String)>,
 8901        edit_preview: &Option<language::EditPreview>,
 8902        snapshot: &language::BufferSnapshot,
 8903        window: &mut Window,
 8904        cx: &mut App,
 8905    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8906        let edit_start = edits
 8907            .first()
 8908            .unwrap()
 8909            .0
 8910            .start
 8911            .to_display_point(editor_snapshot);
 8912        let edit_end = edits
 8913            .last()
 8914            .unwrap()
 8915            .0
 8916            .end
 8917            .to_display_point(editor_snapshot);
 8918
 8919        let is_visible = visible_row_range.contains(&edit_start.row())
 8920            || visible_row_range.contains(&edit_end.row());
 8921        if !is_visible {
 8922            return None;
 8923        }
 8924
 8925        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8926            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8927        } else {
 8928            // Fallback for providers without edit_preview
 8929            crate::edit_prediction_fallback_text(edits, cx)
 8930        };
 8931
 8932        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8933        let line_count = highlighted_edits.text.lines().count();
 8934
 8935        const BORDER_WIDTH: Pixels = px(1.);
 8936
 8937        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8938        let has_keybind = keybind.is_some();
 8939
 8940        let mut element = h_flex()
 8941            .items_start()
 8942            .child(
 8943                h_flex()
 8944                    .bg(cx.theme().colors().editor_background)
 8945                    .border(BORDER_WIDTH)
 8946                    .shadow_xs()
 8947                    .border_color(cx.theme().colors().border)
 8948                    .rounded_l_lg()
 8949                    .when(line_count > 1, |el| el.rounded_br_lg())
 8950                    .pr_1()
 8951                    .child(styled_text),
 8952            )
 8953            .child(
 8954                h_flex()
 8955                    .h(line_height + BORDER_WIDTH * 2.)
 8956                    .px_1p5()
 8957                    .gap_1()
 8958                    // Workaround: For some reason, there's a gap if we don't do this
 8959                    .ml(-BORDER_WIDTH)
 8960                    .shadow(vec![gpui::BoxShadow {
 8961                        color: gpui::black().opacity(0.05),
 8962                        offset: point(px(1.), px(1.)),
 8963                        blur_radius: px(2.),
 8964                        spread_radius: px(0.),
 8965                    }])
 8966                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8967                    .border(BORDER_WIDTH)
 8968                    .border_color(cx.theme().colors().border)
 8969                    .rounded_r_lg()
 8970                    .id("edit_prediction_diff_popover_keybind")
 8971                    .when(!has_keybind, |el| {
 8972                        let status_colors = cx.theme().status();
 8973
 8974                        el.bg(status_colors.error_background)
 8975                            .border_color(status_colors.error.opacity(0.6))
 8976                            .child(Icon::new(IconName::Info).color(Color::Error))
 8977                            .cursor_default()
 8978                            .hoverable_tooltip(move |_window, cx| {
 8979                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8980                            })
 8981                    })
 8982                    .children(keybind),
 8983            )
 8984            .into_any();
 8985
 8986        let longest_row =
 8987            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8988        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8989            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8990        } else {
 8991            layout_line(
 8992                longest_row,
 8993                editor_snapshot,
 8994                style,
 8995                editor_width,
 8996                |_| false,
 8997                window,
 8998                cx,
 8999            )
 9000            .width
 9001        };
 9002
 9003        let viewport_bounds =
 9004            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9005                right: -right_margin,
 9006                ..Default::default()
 9007            });
 9008
 9009        let x_after_longest =
 9010            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9011                - scroll_pixel_position.x;
 9012
 9013        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9014
 9015        // Fully visible if it can be displayed within the window (allow overlapping other
 9016        // panes). However, this is only allowed if the popover starts within text_bounds.
 9017        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9018            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9019
 9020        let mut origin = if can_position_to_the_right {
 9021            point(
 9022                x_after_longest,
 9023                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9024                    - scroll_pixel_position.y,
 9025            )
 9026        } else {
 9027            let cursor_row = newest_selection_head.map(|head| head.row());
 9028            let above_edit = edit_start
 9029                .row()
 9030                .0
 9031                .checked_sub(line_count as u32)
 9032                .map(DisplayRow);
 9033            let below_edit = Some(edit_end.row() + 1);
 9034            let above_cursor =
 9035                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9036            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9037
 9038            // Place the edit popover adjacent to the edit if there is a location
 9039            // available that is onscreen and does not obscure the cursor. Otherwise,
 9040            // place it adjacent to the cursor.
 9041            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9042                .into_iter()
 9043                .flatten()
 9044                .find(|&start_row| {
 9045                    let end_row = start_row + line_count as u32;
 9046                    visible_row_range.contains(&start_row)
 9047                        && visible_row_range.contains(&end_row)
 9048                        && cursor_row
 9049                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9050                })?;
 9051
 9052            content_origin
 9053                + point(
 9054                    -scroll_pixel_position.x,
 9055                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9056                )
 9057        };
 9058
 9059        origin.x -= BORDER_WIDTH;
 9060
 9061        window.defer_draw(element, origin, 1);
 9062
 9063        // Do not return an element, since it will already be drawn due to defer_draw.
 9064        None
 9065    }
 9066
 9067    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9068        px(30.)
 9069    }
 9070
 9071    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9072        if self.read_only(cx) {
 9073            cx.theme().players().read_only()
 9074        } else {
 9075            self.style.as_ref().unwrap().local_player
 9076        }
 9077    }
 9078
 9079    fn render_edit_prediction_accept_keybind(
 9080        &self,
 9081        window: &mut Window,
 9082        cx: &App,
 9083    ) -> Option<AnyElement> {
 9084        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9085        let accept_keystroke = accept_binding.keystroke()?;
 9086
 9087        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9088
 9089        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9090            Color::Accent
 9091        } else {
 9092            Color::Muted
 9093        };
 9094
 9095        h_flex()
 9096            .px_0p5()
 9097            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9098            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9099            .text_size(TextSize::XSmall.rems(cx))
 9100            .child(h_flex().children(ui::render_modifiers(
 9101                accept_keystroke.modifiers(),
 9102                PlatformStyle::platform(),
 9103                Some(modifiers_color),
 9104                Some(IconSize::XSmall.rems().into()),
 9105                true,
 9106            )))
 9107            .when(is_platform_style_mac, |parent| {
 9108                parent.child(accept_keystroke.key().to_string())
 9109            })
 9110            .when(!is_platform_style_mac, |parent| {
 9111                parent.child(
 9112                    Key::new(
 9113                        util::capitalize(accept_keystroke.key()),
 9114                        Some(Color::Default),
 9115                    )
 9116                    .size(Some(IconSize::XSmall.rems().into())),
 9117                )
 9118            })
 9119            .into_any()
 9120            .into()
 9121    }
 9122
 9123    fn render_edit_prediction_line_popover(
 9124        &self,
 9125        label: impl Into<SharedString>,
 9126        icon: Option<IconName>,
 9127        window: &mut Window,
 9128        cx: &App,
 9129    ) -> Option<Stateful<Div>> {
 9130        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9131
 9132        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9133        let has_keybind = keybind.is_some();
 9134
 9135        let result = h_flex()
 9136            .id("ep-line-popover")
 9137            .py_0p5()
 9138            .pl_1()
 9139            .pr(padding_right)
 9140            .gap_1()
 9141            .rounded_md()
 9142            .border_1()
 9143            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9144            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9145            .shadow_xs()
 9146            .when(!has_keybind, |el| {
 9147                let status_colors = cx.theme().status();
 9148
 9149                el.bg(status_colors.error_background)
 9150                    .border_color(status_colors.error.opacity(0.6))
 9151                    .pl_2()
 9152                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9153                    .cursor_default()
 9154                    .hoverable_tooltip(move |_window, cx| {
 9155                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9156                    })
 9157            })
 9158            .children(keybind)
 9159            .child(
 9160                Label::new(label)
 9161                    .size(LabelSize::Small)
 9162                    .when(!has_keybind, |el| {
 9163                        el.color(cx.theme().status().error.into()).strikethrough()
 9164                    }),
 9165            )
 9166            .when(!has_keybind, |el| {
 9167                el.child(
 9168                    h_flex().ml_1().child(
 9169                        Icon::new(IconName::Info)
 9170                            .size(IconSize::Small)
 9171                            .color(cx.theme().status().error.into()),
 9172                    ),
 9173                )
 9174            })
 9175            .when_some(icon, |element, icon| {
 9176                element.child(
 9177                    div()
 9178                        .mt(px(1.5))
 9179                        .child(Icon::new(icon).size(IconSize::Small)),
 9180                )
 9181            });
 9182
 9183        Some(result)
 9184    }
 9185
 9186    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9187        let accent_color = cx.theme().colors().text_accent;
 9188        let editor_bg_color = cx.theme().colors().editor_background;
 9189        editor_bg_color.blend(accent_color.opacity(0.1))
 9190    }
 9191
 9192    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9193        let accent_color = cx.theme().colors().text_accent;
 9194        let editor_bg_color = cx.theme().colors().editor_background;
 9195        editor_bg_color.blend(accent_color.opacity(0.6))
 9196    }
 9197    fn get_prediction_provider_icon_name(
 9198        provider: &Option<RegisteredEditPredictionProvider>,
 9199    ) -> IconName {
 9200        match provider {
 9201            Some(provider) => match provider.provider.name() {
 9202                "copilot" => IconName::Copilot,
 9203                "supermaven" => IconName::Supermaven,
 9204                _ => IconName::ZedPredict,
 9205            },
 9206            None => IconName::ZedPredict,
 9207        }
 9208    }
 9209
 9210    fn render_edit_prediction_cursor_popover(
 9211        &self,
 9212        min_width: Pixels,
 9213        max_width: Pixels,
 9214        cursor_point: Point,
 9215        style: &EditorStyle,
 9216        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9217        _window: &Window,
 9218        cx: &mut Context<Editor>,
 9219    ) -> Option<AnyElement> {
 9220        let provider = self.edit_prediction_provider.as_ref()?;
 9221        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9222
 9223        let is_refreshing = provider.provider.is_refreshing(cx);
 9224
 9225        fn pending_completion_container(icon: IconName) -> Div {
 9226            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9227        }
 9228
 9229        let completion = match &self.active_edit_prediction {
 9230            Some(prediction) => {
 9231                if !self.has_visible_completions_menu() {
 9232                    const RADIUS: Pixels = px(6.);
 9233                    const BORDER_WIDTH: Pixels = px(1.);
 9234
 9235                    return Some(
 9236                        h_flex()
 9237                            .elevation_2(cx)
 9238                            .border(BORDER_WIDTH)
 9239                            .border_color(cx.theme().colors().border)
 9240                            .when(accept_keystroke.is_none(), |el| {
 9241                                el.border_color(cx.theme().status().error)
 9242                            })
 9243                            .rounded(RADIUS)
 9244                            .rounded_tl(px(0.))
 9245                            .overflow_hidden()
 9246                            .child(div().px_1p5().child(match &prediction.completion {
 9247                                EditPrediction::Move { target, snapshot } => {
 9248                                    use text::ToPoint as _;
 9249                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9250                                    {
 9251                                        Icon::new(IconName::ZedPredictDown)
 9252                                    } else {
 9253                                        Icon::new(IconName::ZedPredictUp)
 9254                                    }
 9255                                }
 9256                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9257                            }))
 9258                            .child(
 9259                                h_flex()
 9260                                    .gap_1()
 9261                                    .py_1()
 9262                                    .px_2()
 9263                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9264                                    .border_l_1()
 9265                                    .border_color(cx.theme().colors().border)
 9266                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9267                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9268                                        el.child(
 9269                                            Label::new("Hold")
 9270                                                .size(LabelSize::Small)
 9271                                                .when(accept_keystroke.is_none(), |el| {
 9272                                                    el.strikethrough()
 9273                                                })
 9274                                                .line_height_style(LineHeightStyle::UiLabel),
 9275                                        )
 9276                                    })
 9277                                    .id("edit_prediction_cursor_popover_keybind")
 9278                                    .when(accept_keystroke.is_none(), |el| {
 9279                                        let status_colors = cx.theme().status();
 9280
 9281                                        el.bg(status_colors.error_background)
 9282                                            .border_color(status_colors.error.opacity(0.6))
 9283                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9284                                            .cursor_default()
 9285                                            .hoverable_tooltip(move |_window, cx| {
 9286                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9287                                                    .into()
 9288                                            })
 9289                                    })
 9290                                    .when_some(
 9291                                        accept_keystroke.as_ref(),
 9292                                        |el, accept_keystroke| {
 9293                                            el.child(h_flex().children(ui::render_modifiers(
 9294                                                accept_keystroke.modifiers(),
 9295                                                PlatformStyle::platform(),
 9296                                                Some(Color::Default),
 9297                                                Some(IconSize::XSmall.rems().into()),
 9298                                                false,
 9299                                            )))
 9300                                        },
 9301                                    ),
 9302                            )
 9303                            .into_any(),
 9304                    );
 9305                }
 9306
 9307                self.render_edit_prediction_cursor_popover_preview(
 9308                    prediction,
 9309                    cursor_point,
 9310                    style,
 9311                    cx,
 9312                )?
 9313            }
 9314
 9315            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9316                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9317                    stale_completion,
 9318                    cursor_point,
 9319                    style,
 9320                    cx,
 9321                )?,
 9322
 9323                None => pending_completion_container(provider_icon)
 9324                    .child(Label::new("...").size(LabelSize::Small)),
 9325            },
 9326
 9327            None => pending_completion_container(provider_icon)
 9328                .child(Label::new("...").size(LabelSize::Small)),
 9329        };
 9330
 9331        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9332            completion
 9333                .with_animation(
 9334                    "loading-completion",
 9335                    Animation::new(Duration::from_secs(2))
 9336                        .repeat()
 9337                        .with_easing(pulsating_between(0.4, 0.8)),
 9338                    |label, delta| label.opacity(delta),
 9339                )
 9340                .into_any_element()
 9341        } else {
 9342            completion.into_any_element()
 9343        };
 9344
 9345        let has_completion = self.active_edit_prediction.is_some();
 9346
 9347        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9348        Some(
 9349            h_flex()
 9350                .min_w(min_width)
 9351                .max_w(max_width)
 9352                .flex_1()
 9353                .elevation_2(cx)
 9354                .border_color(cx.theme().colors().border)
 9355                .child(
 9356                    div()
 9357                        .flex_1()
 9358                        .py_1()
 9359                        .px_2()
 9360                        .overflow_hidden()
 9361                        .child(completion),
 9362                )
 9363                .when_some(accept_keystroke, |el, accept_keystroke| {
 9364                    if !accept_keystroke.modifiers().modified() {
 9365                        return el;
 9366                    }
 9367
 9368                    el.child(
 9369                        h_flex()
 9370                            .h_full()
 9371                            .border_l_1()
 9372                            .rounded_r_lg()
 9373                            .border_color(cx.theme().colors().border)
 9374                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9375                            .gap_1()
 9376                            .py_1()
 9377                            .px_2()
 9378                            .child(
 9379                                h_flex()
 9380                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9381                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9382                                    .child(h_flex().children(ui::render_modifiers(
 9383                                        accept_keystroke.modifiers(),
 9384                                        PlatformStyle::platform(),
 9385                                        Some(if !has_completion {
 9386                                            Color::Muted
 9387                                        } else {
 9388                                            Color::Default
 9389                                        }),
 9390                                        None,
 9391                                        false,
 9392                                    ))),
 9393                            )
 9394                            .child(Label::new("Preview").into_any_element())
 9395                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9396                    )
 9397                })
 9398                .into_any(),
 9399        )
 9400    }
 9401
 9402    fn render_edit_prediction_cursor_popover_preview(
 9403        &self,
 9404        completion: &EditPredictionState,
 9405        cursor_point: Point,
 9406        style: &EditorStyle,
 9407        cx: &mut Context<Editor>,
 9408    ) -> Option<Div> {
 9409        use text::ToPoint as _;
 9410
 9411        fn render_relative_row_jump(
 9412            prefix: impl Into<String>,
 9413            current_row: u32,
 9414            target_row: u32,
 9415        ) -> Div {
 9416            let (row_diff, arrow) = if target_row < current_row {
 9417                (current_row - target_row, IconName::ArrowUp)
 9418            } else {
 9419                (target_row - current_row, IconName::ArrowDown)
 9420            };
 9421
 9422            h_flex()
 9423                .child(
 9424                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9425                        .color(Color::Muted)
 9426                        .size(LabelSize::Small),
 9427                )
 9428                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9429        }
 9430
 9431        let supports_jump = self
 9432            .edit_prediction_provider
 9433            .as_ref()
 9434            .map(|provider| provider.provider.supports_jump_to_edit())
 9435            .unwrap_or(true);
 9436
 9437        match &completion.completion {
 9438            EditPrediction::Move {
 9439                target, snapshot, ..
 9440            } => {
 9441                if !supports_jump {
 9442                    return None;
 9443                }
 9444
 9445                Some(
 9446                    h_flex()
 9447                        .px_2()
 9448                        .gap_2()
 9449                        .flex_1()
 9450                        .child(
 9451                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9452                                Icon::new(IconName::ZedPredictDown)
 9453                            } else {
 9454                                Icon::new(IconName::ZedPredictUp)
 9455                            },
 9456                        )
 9457                        .child(Label::new("Jump to Edit")),
 9458                )
 9459            }
 9460
 9461            EditPrediction::Edit {
 9462                edits,
 9463                edit_preview,
 9464                snapshot,
 9465                display_mode: _,
 9466            } => {
 9467                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9468
 9469                let (highlighted_edits, has_more_lines) =
 9470                    if let Some(edit_preview) = edit_preview.as_ref() {
 9471                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9472                            .first_line_preview()
 9473                    } else {
 9474                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9475                    };
 9476
 9477                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9478                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9479
 9480                let preview = h_flex()
 9481                    .gap_1()
 9482                    .min_w_16()
 9483                    .child(styled_text)
 9484                    .when(has_more_lines, |parent| parent.child(""));
 9485
 9486                let left = if supports_jump && first_edit_row != cursor_point.row {
 9487                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9488                        .into_any_element()
 9489                } else {
 9490                    let icon_name =
 9491                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9492                    Icon::new(icon_name).into_any_element()
 9493                };
 9494
 9495                Some(
 9496                    h_flex()
 9497                        .h_full()
 9498                        .flex_1()
 9499                        .gap_2()
 9500                        .pr_1()
 9501                        .overflow_x_hidden()
 9502                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9503                        .child(left)
 9504                        .child(preview),
 9505                )
 9506            }
 9507        }
 9508    }
 9509
 9510    pub fn render_context_menu(
 9511        &self,
 9512        style: &EditorStyle,
 9513        max_height_in_lines: u32,
 9514        window: &mut Window,
 9515        cx: &mut Context<Editor>,
 9516    ) -> Option<AnyElement> {
 9517        let menu = self.context_menu.borrow();
 9518        let menu = menu.as_ref()?;
 9519        if !menu.visible() {
 9520            return None;
 9521        };
 9522        Some(menu.render(style, max_height_in_lines, window, cx))
 9523    }
 9524
 9525    fn render_context_menu_aside(
 9526        &mut self,
 9527        max_size: Size<Pixels>,
 9528        window: &mut Window,
 9529        cx: &mut Context<Editor>,
 9530    ) -> Option<AnyElement> {
 9531        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9532            if menu.visible() {
 9533                menu.render_aside(max_size, window, cx)
 9534            } else {
 9535                None
 9536            }
 9537        })
 9538    }
 9539
 9540    fn hide_context_menu(
 9541        &mut self,
 9542        window: &mut Window,
 9543        cx: &mut Context<Self>,
 9544    ) -> Option<CodeContextMenu> {
 9545        cx.notify();
 9546        self.completion_tasks.clear();
 9547        let context_menu = self.context_menu.borrow_mut().take();
 9548        self.stale_edit_prediction_in_menu.take();
 9549        self.update_visible_edit_prediction(window, cx);
 9550        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9551            && let Some(completion_provider) = &self.completion_provider
 9552        {
 9553            completion_provider.selection_changed(None, window, cx);
 9554        }
 9555        context_menu
 9556    }
 9557
 9558    fn show_snippet_choices(
 9559        &mut self,
 9560        choices: &Vec<String>,
 9561        selection: Range<Anchor>,
 9562        cx: &mut Context<Self>,
 9563    ) {
 9564        let Some((_, buffer, _)) = self
 9565            .buffer()
 9566            .read(cx)
 9567            .excerpt_containing(selection.start, cx)
 9568        else {
 9569            return;
 9570        };
 9571        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9572        else {
 9573            return;
 9574        };
 9575        if buffer != end_buffer {
 9576            log::error!("expected anchor range to have matching buffer IDs");
 9577            return;
 9578        }
 9579
 9580        let id = post_inc(&mut self.next_completion_id);
 9581        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9582        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9583            CompletionsMenu::new_snippet_choices(
 9584                id,
 9585                true,
 9586                choices,
 9587                selection,
 9588                buffer,
 9589                snippet_sort_order,
 9590            ),
 9591        ));
 9592    }
 9593
 9594    pub fn insert_snippet(
 9595        &mut self,
 9596        insertion_ranges: &[Range<usize>],
 9597        snippet: Snippet,
 9598        window: &mut Window,
 9599        cx: &mut Context<Self>,
 9600    ) -> Result<()> {
 9601        struct Tabstop<T> {
 9602            is_end_tabstop: bool,
 9603            ranges: Vec<Range<T>>,
 9604            choices: Option<Vec<String>>,
 9605        }
 9606
 9607        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9608            let snippet_text: Arc<str> = snippet.text.clone().into();
 9609            let edits = insertion_ranges
 9610                .iter()
 9611                .cloned()
 9612                .map(|range| (range, snippet_text.clone()));
 9613            let autoindent_mode = AutoindentMode::Block {
 9614                original_indent_columns: Vec::new(),
 9615            };
 9616            buffer.edit(edits, Some(autoindent_mode), cx);
 9617
 9618            let snapshot = &*buffer.read(cx);
 9619            let snippet = &snippet;
 9620            snippet
 9621                .tabstops
 9622                .iter()
 9623                .map(|tabstop| {
 9624                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9625                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9626                    });
 9627                    let mut tabstop_ranges = tabstop
 9628                        .ranges
 9629                        .iter()
 9630                        .flat_map(|tabstop_range| {
 9631                            let mut delta = 0_isize;
 9632                            insertion_ranges.iter().map(move |insertion_range| {
 9633                                let insertion_start = insertion_range.start as isize + delta;
 9634                                delta +=
 9635                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9636
 9637                                let start = ((insertion_start + tabstop_range.start) as usize)
 9638                                    .min(snapshot.len());
 9639                                let end = ((insertion_start + tabstop_range.end) as usize)
 9640                                    .min(snapshot.len());
 9641                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9642                            })
 9643                        })
 9644                        .collect::<Vec<_>>();
 9645                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9646
 9647                    Tabstop {
 9648                        is_end_tabstop,
 9649                        ranges: tabstop_ranges,
 9650                        choices: tabstop.choices.clone(),
 9651                    }
 9652                })
 9653                .collect::<Vec<_>>()
 9654        });
 9655        if let Some(tabstop) = tabstops.first() {
 9656            self.change_selections(Default::default(), window, cx, |s| {
 9657                // Reverse order so that the first range is the newest created selection.
 9658                // Completions will use it and autoscroll will prioritize it.
 9659                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9660            });
 9661
 9662            if let Some(choices) = &tabstop.choices
 9663                && let Some(selection) = tabstop.ranges.first()
 9664            {
 9665                self.show_snippet_choices(choices, selection.clone(), cx)
 9666            }
 9667
 9668            // If we're already at the last tabstop and it's at the end of the snippet,
 9669            // we're done, we don't need to keep the state around.
 9670            if !tabstop.is_end_tabstop {
 9671                let choices = tabstops
 9672                    .iter()
 9673                    .map(|tabstop| tabstop.choices.clone())
 9674                    .collect();
 9675
 9676                let ranges = tabstops
 9677                    .into_iter()
 9678                    .map(|tabstop| tabstop.ranges)
 9679                    .collect::<Vec<_>>();
 9680
 9681                self.snippet_stack.push(SnippetState {
 9682                    active_index: 0,
 9683                    ranges,
 9684                    choices,
 9685                });
 9686            }
 9687
 9688            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9689            if self.autoclose_regions.is_empty() {
 9690                let snapshot = self.buffer.read(cx).snapshot(cx);
 9691                let mut all_selections = self.selections.all::<Point>(cx);
 9692                for selection in &mut all_selections {
 9693                    let selection_head = selection.head();
 9694                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9695                        continue;
 9696                    };
 9697
 9698                    let mut bracket_pair = None;
 9699                    let max_lookup_length = scope
 9700                        .brackets()
 9701                        .map(|(pair, _)| {
 9702                            pair.start
 9703                                .as_str()
 9704                                .chars()
 9705                                .count()
 9706                                .max(pair.end.as_str().chars().count())
 9707                        })
 9708                        .max();
 9709                    if let Some(max_lookup_length) = max_lookup_length {
 9710                        let next_text = snapshot
 9711                            .chars_at(selection_head)
 9712                            .take(max_lookup_length)
 9713                            .collect::<String>();
 9714                        let prev_text = snapshot
 9715                            .reversed_chars_at(selection_head)
 9716                            .take(max_lookup_length)
 9717                            .collect::<String>();
 9718
 9719                        for (pair, enabled) in scope.brackets() {
 9720                            if enabled
 9721                                && pair.close
 9722                                && prev_text.starts_with(pair.start.as_str())
 9723                                && next_text.starts_with(pair.end.as_str())
 9724                            {
 9725                                bracket_pair = Some(pair.clone());
 9726                                break;
 9727                            }
 9728                        }
 9729                    }
 9730
 9731                    if let Some(pair) = bracket_pair {
 9732                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9733                        let autoclose_enabled =
 9734                            self.use_autoclose && snapshot_settings.use_autoclose;
 9735                        if autoclose_enabled {
 9736                            let start = snapshot.anchor_after(selection_head);
 9737                            let end = snapshot.anchor_after(selection_head);
 9738                            self.autoclose_regions.push(AutocloseRegion {
 9739                                selection_id: selection.id,
 9740                                range: start..end,
 9741                                pair,
 9742                            });
 9743                        }
 9744                    }
 9745                }
 9746            }
 9747        }
 9748        Ok(())
 9749    }
 9750
 9751    pub fn move_to_next_snippet_tabstop(
 9752        &mut self,
 9753        window: &mut Window,
 9754        cx: &mut Context<Self>,
 9755    ) -> bool {
 9756        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9757    }
 9758
 9759    pub fn move_to_prev_snippet_tabstop(
 9760        &mut self,
 9761        window: &mut Window,
 9762        cx: &mut Context<Self>,
 9763    ) -> bool {
 9764        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9765    }
 9766
 9767    pub fn move_to_snippet_tabstop(
 9768        &mut self,
 9769        bias: Bias,
 9770        window: &mut Window,
 9771        cx: &mut Context<Self>,
 9772    ) -> bool {
 9773        if let Some(mut snippet) = self.snippet_stack.pop() {
 9774            match bias {
 9775                Bias::Left => {
 9776                    if snippet.active_index > 0 {
 9777                        snippet.active_index -= 1;
 9778                    } else {
 9779                        self.snippet_stack.push(snippet);
 9780                        return false;
 9781                    }
 9782                }
 9783                Bias::Right => {
 9784                    if snippet.active_index + 1 < snippet.ranges.len() {
 9785                        snippet.active_index += 1;
 9786                    } else {
 9787                        self.snippet_stack.push(snippet);
 9788                        return false;
 9789                    }
 9790                }
 9791            }
 9792            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9793                self.change_selections(Default::default(), window, cx, |s| {
 9794                    // Reverse order so that the first range is the newest created selection.
 9795                    // Completions will use it and autoscroll will prioritize it.
 9796                    s.select_ranges(current_ranges.iter().rev().cloned())
 9797                });
 9798
 9799                if let Some(choices) = &snippet.choices[snippet.active_index]
 9800                    && let Some(selection) = current_ranges.first()
 9801                {
 9802                    self.show_snippet_choices(choices, selection.clone(), cx);
 9803                }
 9804
 9805                // If snippet state is not at the last tabstop, push it back on the stack
 9806                if snippet.active_index + 1 < snippet.ranges.len() {
 9807                    self.snippet_stack.push(snippet);
 9808                }
 9809                return true;
 9810            }
 9811        }
 9812
 9813        false
 9814    }
 9815
 9816    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9817        self.transact(window, cx, |this, window, cx| {
 9818            this.select_all(&SelectAll, window, cx);
 9819            this.insert("", window, cx);
 9820        });
 9821    }
 9822
 9823    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9824        if self.read_only(cx) {
 9825            return;
 9826        }
 9827        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9828        self.transact(window, cx, |this, window, cx| {
 9829            this.select_autoclose_pair(window, cx);
 9830            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9831            if !this.linked_edit_ranges.is_empty() {
 9832                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9833                let snapshot = this.buffer.read(cx).snapshot(cx);
 9834
 9835                for selection in selections.iter() {
 9836                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9837                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9838                    if selection_start.buffer_id != selection_end.buffer_id {
 9839                        continue;
 9840                    }
 9841                    if let Some(ranges) =
 9842                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9843                    {
 9844                        for (buffer, entries) in ranges {
 9845                            linked_ranges.entry(buffer).or_default().extend(entries);
 9846                        }
 9847                    }
 9848                }
 9849            }
 9850
 9851            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9852            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9853            for selection in &mut selections {
 9854                if selection.is_empty() {
 9855                    let old_head = selection.head();
 9856                    let mut new_head =
 9857                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9858                            .to_point(&display_map);
 9859                    if let Some((buffer, line_buffer_range)) = display_map
 9860                        .buffer_snapshot
 9861                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9862                    {
 9863                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9864                        let indent_len = match indent_size.kind {
 9865                            IndentKind::Space => {
 9866                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9867                            }
 9868                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9869                        };
 9870                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9871                            let indent_len = indent_len.get();
 9872                            new_head = cmp::min(
 9873                                new_head,
 9874                                MultiBufferPoint::new(
 9875                                    old_head.row,
 9876                                    ((old_head.column - 1) / indent_len) * indent_len,
 9877                                ),
 9878                            );
 9879                        }
 9880                    }
 9881
 9882                    selection.set_head(new_head, SelectionGoal::None);
 9883                }
 9884            }
 9885
 9886            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9887            this.insert("", window, cx);
 9888            let empty_str: Arc<str> = Arc::from("");
 9889            for (buffer, edits) in linked_ranges {
 9890                let snapshot = buffer.read(cx).snapshot();
 9891                use text::ToPoint as TP;
 9892
 9893                let edits = edits
 9894                    .into_iter()
 9895                    .map(|range| {
 9896                        let end_point = TP::to_point(&range.end, &snapshot);
 9897                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9898
 9899                        if end_point == start_point {
 9900                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9901                                .saturating_sub(1);
 9902                            start_point =
 9903                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9904                        };
 9905
 9906                        (start_point..end_point, empty_str.clone())
 9907                    })
 9908                    .sorted_by_key(|(range, _)| range.start)
 9909                    .collect::<Vec<_>>();
 9910                buffer.update(cx, |this, cx| {
 9911                    this.edit(edits, None, cx);
 9912                })
 9913            }
 9914            this.refresh_edit_prediction(true, false, window, cx);
 9915            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9916        });
 9917    }
 9918
 9919    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9920        if self.read_only(cx) {
 9921            return;
 9922        }
 9923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9924        self.transact(window, cx, |this, window, cx| {
 9925            this.change_selections(Default::default(), window, cx, |s| {
 9926                s.move_with(|map, selection| {
 9927                    if selection.is_empty() {
 9928                        let cursor = movement::right(map, selection.head());
 9929                        selection.end = cursor;
 9930                        selection.reversed = true;
 9931                        selection.goal = SelectionGoal::None;
 9932                    }
 9933                })
 9934            });
 9935            this.insert("", window, cx);
 9936            this.refresh_edit_prediction(true, false, window, cx);
 9937        });
 9938    }
 9939
 9940    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9941        if self.mode.is_single_line() {
 9942            cx.propagate();
 9943            return;
 9944        }
 9945
 9946        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9947        if self.move_to_prev_snippet_tabstop(window, cx) {
 9948            return;
 9949        }
 9950        self.outdent(&Outdent, window, cx);
 9951    }
 9952
 9953    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9954        if self.mode.is_single_line() {
 9955            cx.propagate();
 9956            return;
 9957        }
 9958
 9959        if self.move_to_next_snippet_tabstop(window, cx) {
 9960            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9961            return;
 9962        }
 9963        if self.read_only(cx) {
 9964            return;
 9965        }
 9966        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9967        let mut selections = self.selections.all_adjusted(cx);
 9968        let buffer = self.buffer.read(cx);
 9969        let snapshot = buffer.snapshot(cx);
 9970        let rows_iter = selections.iter().map(|s| s.head().row);
 9971        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9972
 9973        let has_some_cursor_in_whitespace = selections
 9974            .iter()
 9975            .filter(|selection| selection.is_empty())
 9976            .any(|selection| {
 9977                let cursor = selection.head();
 9978                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9979                cursor.column < current_indent.len
 9980            });
 9981
 9982        let mut edits = Vec::new();
 9983        let mut prev_edited_row = 0;
 9984        let mut row_delta = 0;
 9985        for selection in &mut selections {
 9986            if selection.start.row != prev_edited_row {
 9987                row_delta = 0;
 9988            }
 9989            prev_edited_row = selection.end.row;
 9990
 9991            // If the selection is non-empty, then increase the indentation of the selected lines.
 9992            if !selection.is_empty() {
 9993                row_delta =
 9994                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9995                continue;
 9996            }
 9997
 9998            let cursor = selection.head();
 9999            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10000            if let Some(suggested_indent) =
10001                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10002            {
10003                // Don't do anything if already at suggested indent
10004                // and there is any other cursor which is not
10005                if has_some_cursor_in_whitespace
10006                    && cursor.column == current_indent.len
10007                    && current_indent.len == suggested_indent.len
10008                {
10009                    continue;
10010                }
10011
10012                // Adjust line and move cursor to suggested indent
10013                // if cursor is not at suggested indent
10014                if cursor.column < suggested_indent.len
10015                    && cursor.column <= current_indent.len
10016                    && current_indent.len <= suggested_indent.len
10017                {
10018                    selection.start = Point::new(cursor.row, suggested_indent.len);
10019                    selection.end = selection.start;
10020                    if row_delta == 0 {
10021                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10022                            cursor.row,
10023                            current_indent,
10024                            suggested_indent,
10025                        ));
10026                        row_delta = suggested_indent.len - current_indent.len;
10027                    }
10028                    continue;
10029                }
10030
10031                // If current indent is more than suggested indent
10032                // only move cursor to current indent and skip indent
10033                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10034                    selection.start = Point::new(cursor.row, current_indent.len);
10035                    selection.end = selection.start;
10036                    continue;
10037                }
10038            }
10039
10040            // Otherwise, insert a hard or soft tab.
10041            let settings = buffer.language_settings_at(cursor, cx);
10042            let tab_size = if settings.hard_tabs {
10043                IndentSize::tab()
10044            } else {
10045                let tab_size = settings.tab_size.get();
10046                let indent_remainder = snapshot
10047                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10048                    .flat_map(str::chars)
10049                    .fold(row_delta % tab_size, |counter: u32, c| {
10050                        if c == '\t' {
10051                            0
10052                        } else {
10053                            (counter + 1) % tab_size
10054                        }
10055                    });
10056
10057                let chars_to_next_tab_stop = tab_size - indent_remainder;
10058                IndentSize::spaces(chars_to_next_tab_stop)
10059            };
10060            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10061            selection.end = selection.start;
10062            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10063            row_delta += tab_size.len;
10064        }
10065
10066        self.transact(window, cx, |this, window, cx| {
10067            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10068            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10069            this.refresh_edit_prediction(true, false, window, cx);
10070        });
10071    }
10072
10073    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10074        if self.read_only(cx) {
10075            return;
10076        }
10077        if self.mode.is_single_line() {
10078            cx.propagate();
10079            return;
10080        }
10081
10082        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10083        let mut selections = self.selections.all::<Point>(cx);
10084        let mut prev_edited_row = 0;
10085        let mut row_delta = 0;
10086        let mut edits = Vec::new();
10087        let buffer = self.buffer.read(cx);
10088        let snapshot = buffer.snapshot(cx);
10089        for selection in &mut selections {
10090            if selection.start.row != prev_edited_row {
10091                row_delta = 0;
10092            }
10093            prev_edited_row = selection.end.row;
10094
10095            row_delta =
10096                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10097        }
10098
10099        self.transact(window, cx, |this, window, cx| {
10100            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10101            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10102        });
10103    }
10104
10105    fn indent_selection(
10106        buffer: &MultiBuffer,
10107        snapshot: &MultiBufferSnapshot,
10108        selection: &mut Selection<Point>,
10109        edits: &mut Vec<(Range<Point>, String)>,
10110        delta_for_start_row: u32,
10111        cx: &App,
10112    ) -> u32 {
10113        let settings = buffer.language_settings_at(selection.start, cx);
10114        let tab_size = settings.tab_size.get();
10115        let indent_kind = if settings.hard_tabs {
10116            IndentKind::Tab
10117        } else {
10118            IndentKind::Space
10119        };
10120        let mut start_row = selection.start.row;
10121        let mut end_row = selection.end.row + 1;
10122
10123        // If a selection ends at the beginning of a line, don't indent
10124        // that last line.
10125        if selection.end.column == 0 && selection.end.row > selection.start.row {
10126            end_row -= 1;
10127        }
10128
10129        // Avoid re-indenting a row that has already been indented by a
10130        // previous selection, but still update this selection's column
10131        // to reflect that indentation.
10132        if delta_for_start_row > 0 {
10133            start_row += 1;
10134            selection.start.column += delta_for_start_row;
10135            if selection.end.row == selection.start.row {
10136                selection.end.column += delta_for_start_row;
10137            }
10138        }
10139
10140        let mut delta_for_end_row = 0;
10141        let has_multiple_rows = start_row + 1 != end_row;
10142        for row in start_row..end_row {
10143            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10144            let indent_delta = match (current_indent.kind, indent_kind) {
10145                (IndentKind::Space, IndentKind::Space) => {
10146                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10147                    IndentSize::spaces(columns_to_next_tab_stop)
10148                }
10149                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10150                (_, IndentKind::Tab) => IndentSize::tab(),
10151            };
10152
10153            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10154                0
10155            } else {
10156                selection.start.column
10157            };
10158            let row_start = Point::new(row, start);
10159            edits.push((
10160                row_start..row_start,
10161                indent_delta.chars().collect::<String>(),
10162            ));
10163
10164            // Update this selection's endpoints to reflect the indentation.
10165            if row == selection.start.row {
10166                selection.start.column += indent_delta.len;
10167            }
10168            if row == selection.end.row {
10169                selection.end.column += indent_delta.len;
10170                delta_for_end_row = indent_delta.len;
10171            }
10172        }
10173
10174        if selection.start.row == selection.end.row {
10175            delta_for_start_row + delta_for_end_row
10176        } else {
10177            delta_for_end_row
10178        }
10179    }
10180
10181    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10182        if self.read_only(cx) {
10183            return;
10184        }
10185        if self.mode.is_single_line() {
10186            cx.propagate();
10187            return;
10188        }
10189
10190        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10191        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10192        let selections = self.selections.all::<Point>(cx);
10193        let mut deletion_ranges = Vec::new();
10194        let mut last_outdent = None;
10195        {
10196            let buffer = self.buffer.read(cx);
10197            let snapshot = buffer.snapshot(cx);
10198            for selection in &selections {
10199                let settings = buffer.language_settings_at(selection.start, cx);
10200                let tab_size = settings.tab_size.get();
10201                let mut rows = selection.spanned_rows(false, &display_map);
10202
10203                // Avoid re-outdenting a row that has already been outdented by a
10204                // previous selection.
10205                if let Some(last_row) = last_outdent
10206                    && last_row == rows.start
10207                {
10208                    rows.start = rows.start.next_row();
10209                }
10210                let has_multiple_rows = rows.len() > 1;
10211                for row in rows.iter_rows() {
10212                    let indent_size = snapshot.indent_size_for_line(row);
10213                    if indent_size.len > 0 {
10214                        let deletion_len = match indent_size.kind {
10215                            IndentKind::Space => {
10216                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10217                                if columns_to_prev_tab_stop == 0 {
10218                                    tab_size
10219                                } else {
10220                                    columns_to_prev_tab_stop
10221                                }
10222                            }
10223                            IndentKind::Tab => 1,
10224                        };
10225                        let start = if has_multiple_rows
10226                            || deletion_len > selection.start.column
10227                            || indent_size.len < selection.start.column
10228                        {
10229                            0
10230                        } else {
10231                            selection.start.column - deletion_len
10232                        };
10233                        deletion_ranges.push(
10234                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10235                        );
10236                        last_outdent = Some(row);
10237                    }
10238                }
10239            }
10240        }
10241
10242        self.transact(window, cx, |this, window, cx| {
10243            this.buffer.update(cx, |buffer, cx| {
10244                let empty_str: Arc<str> = Arc::default();
10245                buffer.edit(
10246                    deletion_ranges
10247                        .into_iter()
10248                        .map(|range| (range, empty_str.clone())),
10249                    None,
10250                    cx,
10251                );
10252            });
10253            let selections = this.selections.all::<usize>(cx);
10254            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10255        });
10256    }
10257
10258    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10259        if self.read_only(cx) {
10260            return;
10261        }
10262        if self.mode.is_single_line() {
10263            cx.propagate();
10264            return;
10265        }
10266
10267        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10268        let selections = self
10269            .selections
10270            .all::<usize>(cx)
10271            .into_iter()
10272            .map(|s| s.range());
10273
10274        self.transact(window, cx, |this, window, cx| {
10275            this.buffer.update(cx, |buffer, cx| {
10276                buffer.autoindent_ranges(selections, cx);
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 delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10284        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10285        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10286        let selections = self.selections.all::<Point>(cx);
10287
10288        let mut new_cursors = Vec::new();
10289        let mut edit_ranges = Vec::new();
10290        let mut selections = selections.iter().peekable();
10291        while let Some(selection) = selections.next() {
10292            let mut rows = selection.spanned_rows(false, &display_map);
10293            let goal_display_column = selection.head().to_display_point(&display_map).column();
10294
10295            // Accumulate contiguous regions of rows that we want to delete.
10296            while let Some(next_selection) = selections.peek() {
10297                let next_rows = next_selection.spanned_rows(false, &display_map);
10298                if next_rows.start <= rows.end {
10299                    rows.end = next_rows.end;
10300                    selections.next().unwrap();
10301                } else {
10302                    break;
10303                }
10304            }
10305
10306            let buffer = &display_map.buffer_snapshot;
10307            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10308            let edit_end;
10309            let cursor_buffer_row;
10310            if buffer.max_point().row >= rows.end.0 {
10311                // If there's a line after the range, delete the \n from the end of the row range
10312                // and position the cursor on the next line.
10313                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10314                cursor_buffer_row = rows.end;
10315            } else {
10316                // If there isn't a line after the range, delete the \n from the line before the
10317                // start of the row range and position the cursor there.
10318                edit_start = edit_start.saturating_sub(1);
10319                edit_end = buffer.len();
10320                cursor_buffer_row = rows.start.previous_row();
10321            }
10322
10323            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10324            *cursor.column_mut() =
10325                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10326
10327            new_cursors.push((
10328                selection.id,
10329                buffer.anchor_after(cursor.to_point(&display_map)),
10330            ));
10331            edit_ranges.push(edit_start..edit_end);
10332        }
10333
10334        self.transact(window, cx, |this, window, cx| {
10335            let buffer = this.buffer.update(cx, |buffer, cx| {
10336                let empty_str: Arc<str> = Arc::default();
10337                buffer.edit(
10338                    edit_ranges
10339                        .into_iter()
10340                        .map(|range| (range, empty_str.clone())),
10341                    None,
10342                    cx,
10343                );
10344                buffer.snapshot(cx)
10345            });
10346            let new_selections = new_cursors
10347                .into_iter()
10348                .map(|(id, cursor)| {
10349                    let cursor = cursor.to_point(&buffer);
10350                    Selection {
10351                        id,
10352                        start: cursor,
10353                        end: cursor,
10354                        reversed: false,
10355                        goal: SelectionGoal::None,
10356                    }
10357                })
10358                .collect();
10359
10360            this.change_selections(Default::default(), window, cx, |s| {
10361                s.select(new_selections);
10362            });
10363        });
10364    }
10365
10366    pub fn join_lines_impl(
10367        &mut self,
10368        insert_whitespace: bool,
10369        window: &mut Window,
10370        cx: &mut Context<Self>,
10371    ) {
10372        if self.read_only(cx) {
10373            return;
10374        }
10375        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10376        for selection in self.selections.all::<Point>(cx) {
10377            let start = MultiBufferRow(selection.start.row);
10378            // Treat single line selections as if they include the next line. Otherwise this action
10379            // would do nothing for single line selections individual cursors.
10380            let end = if selection.start.row == selection.end.row {
10381                MultiBufferRow(selection.start.row + 1)
10382            } else {
10383                MultiBufferRow(selection.end.row)
10384            };
10385
10386            if let Some(last_row_range) = row_ranges.last_mut()
10387                && start <= last_row_range.end
10388            {
10389                last_row_range.end = end;
10390                continue;
10391            }
10392            row_ranges.push(start..end);
10393        }
10394
10395        let snapshot = self.buffer.read(cx).snapshot(cx);
10396        let mut cursor_positions = Vec::new();
10397        for row_range in &row_ranges {
10398            let anchor = snapshot.anchor_before(Point::new(
10399                row_range.end.previous_row().0,
10400                snapshot.line_len(row_range.end.previous_row()),
10401            ));
10402            cursor_positions.push(anchor..anchor);
10403        }
10404
10405        self.transact(window, cx, |this, window, cx| {
10406            for row_range in row_ranges.into_iter().rev() {
10407                for row in row_range.iter_rows().rev() {
10408                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10409                    let next_line_row = row.next_row();
10410                    let indent = snapshot.indent_size_for_line(next_line_row);
10411                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10412
10413                    let replace =
10414                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10415                            " "
10416                        } else {
10417                            ""
10418                        };
10419
10420                    this.buffer.update(cx, |buffer, cx| {
10421                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10422                    });
10423                }
10424            }
10425
10426            this.change_selections(Default::default(), window, cx, |s| {
10427                s.select_anchor_ranges(cursor_positions)
10428            });
10429        });
10430    }
10431
10432    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10433        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10434        self.join_lines_impl(true, window, cx);
10435    }
10436
10437    pub fn sort_lines_case_sensitive(
10438        &mut self,
10439        _: &SortLinesCaseSensitive,
10440        window: &mut Window,
10441        cx: &mut Context<Self>,
10442    ) {
10443        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10444    }
10445
10446    pub fn sort_lines_by_length(
10447        &mut self,
10448        _: &SortLinesByLength,
10449        window: &mut Window,
10450        cx: &mut Context<Self>,
10451    ) {
10452        self.manipulate_immutable_lines(window, cx, |lines| {
10453            lines.sort_by_key(|&line| line.chars().count())
10454        })
10455    }
10456
10457    pub fn sort_lines_case_insensitive(
10458        &mut self,
10459        _: &SortLinesCaseInsensitive,
10460        window: &mut Window,
10461        cx: &mut Context<Self>,
10462    ) {
10463        self.manipulate_immutable_lines(window, cx, |lines| {
10464            lines.sort_by_key(|line| line.to_lowercase())
10465        })
10466    }
10467
10468    pub fn unique_lines_case_insensitive(
10469        &mut self,
10470        _: &UniqueLinesCaseInsensitive,
10471        window: &mut Window,
10472        cx: &mut Context<Self>,
10473    ) {
10474        self.manipulate_immutable_lines(window, cx, |lines| {
10475            let mut seen = HashSet::default();
10476            lines.retain(|line| seen.insert(line.to_lowercase()));
10477        })
10478    }
10479
10480    pub fn unique_lines_case_sensitive(
10481        &mut self,
10482        _: &UniqueLinesCaseSensitive,
10483        window: &mut Window,
10484        cx: &mut Context<Self>,
10485    ) {
10486        self.manipulate_immutable_lines(window, cx, |lines| {
10487            let mut seen = HashSet::default();
10488            lines.retain(|line| seen.insert(*line));
10489        })
10490    }
10491
10492    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10493        let snapshot = self.buffer.read(cx).snapshot(cx);
10494        for selection in self.selections.disjoint_anchors().iter() {
10495            if snapshot
10496                .language_at(selection.start)
10497                .and_then(|lang| lang.config().wrap_characters.as_ref())
10498                .is_some()
10499            {
10500                return true;
10501            }
10502        }
10503        false
10504    }
10505
10506    fn wrap_selections_in_tag(
10507        &mut self,
10508        _: &WrapSelectionsInTag,
10509        window: &mut Window,
10510        cx: &mut Context<Self>,
10511    ) {
10512        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10513
10514        let snapshot = self.buffer.read(cx).snapshot(cx);
10515
10516        let mut edits = Vec::new();
10517        let mut boundaries = Vec::new();
10518
10519        for selection in self.selections.all::<Point>(cx).iter() {
10520            let Some(wrap_config) = snapshot
10521                .language_at(selection.start)
10522                .and_then(|lang| lang.config().wrap_characters.clone())
10523            else {
10524                continue;
10525            };
10526
10527            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10528            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10529
10530            let start_before = snapshot.anchor_before(selection.start);
10531            let end_after = snapshot.anchor_after(selection.end);
10532
10533            edits.push((start_before..start_before, open_tag));
10534            edits.push((end_after..end_after, close_tag));
10535
10536            boundaries.push((
10537                start_before,
10538                end_after,
10539                wrap_config.start_prefix.len(),
10540                wrap_config.end_suffix.len(),
10541            ));
10542        }
10543
10544        if edits.is_empty() {
10545            return;
10546        }
10547
10548        self.transact(window, cx, |this, window, cx| {
10549            let buffer = this.buffer.update(cx, |buffer, cx| {
10550                buffer.edit(edits, None, cx);
10551                buffer.snapshot(cx)
10552            });
10553
10554            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10555            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10556                boundaries.into_iter()
10557            {
10558                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10559                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10560                new_selections.push(open_offset..open_offset);
10561                new_selections.push(close_offset..close_offset);
10562            }
10563
10564            this.change_selections(Default::default(), window, cx, |s| {
10565                s.select_ranges(new_selections);
10566            });
10567
10568            this.request_autoscroll(Autoscroll::fit(), cx);
10569        });
10570    }
10571
10572    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10573        let Some(project) = self.project.clone() else {
10574            return;
10575        };
10576        self.reload(project, window, cx)
10577            .detach_and_notify_err(window, cx);
10578    }
10579
10580    pub fn restore_file(
10581        &mut self,
10582        _: &::git::RestoreFile,
10583        window: &mut Window,
10584        cx: &mut Context<Self>,
10585    ) {
10586        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10587        let mut buffer_ids = HashSet::default();
10588        let snapshot = self.buffer().read(cx).snapshot(cx);
10589        for selection in self.selections.all::<usize>(cx) {
10590            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10591        }
10592
10593        let buffer = self.buffer().read(cx);
10594        let ranges = buffer_ids
10595            .into_iter()
10596            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10597            .collect::<Vec<_>>();
10598
10599        self.restore_hunks_in_ranges(ranges, window, cx);
10600    }
10601
10602    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10603        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10604        let selections = self
10605            .selections
10606            .all(cx)
10607            .into_iter()
10608            .map(|s| s.range())
10609            .collect();
10610        self.restore_hunks_in_ranges(selections, window, cx);
10611    }
10612
10613    pub fn restore_hunks_in_ranges(
10614        &mut self,
10615        ranges: Vec<Range<Point>>,
10616        window: &mut Window,
10617        cx: &mut Context<Editor>,
10618    ) {
10619        let mut revert_changes = HashMap::default();
10620        let chunk_by = self
10621            .snapshot(window, cx)
10622            .hunks_for_ranges(ranges)
10623            .into_iter()
10624            .chunk_by(|hunk| hunk.buffer_id);
10625        for (buffer_id, hunks) in &chunk_by {
10626            let hunks = hunks.collect::<Vec<_>>();
10627            for hunk in &hunks {
10628                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10629            }
10630            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10631        }
10632        drop(chunk_by);
10633        if !revert_changes.is_empty() {
10634            self.transact(window, cx, |editor, window, cx| {
10635                editor.restore(revert_changes, window, cx);
10636            });
10637        }
10638    }
10639
10640    pub fn open_active_item_in_terminal(
10641        &mut self,
10642        _: &OpenInTerminal,
10643        window: &mut Window,
10644        cx: &mut Context<Self>,
10645    ) {
10646        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10647            let project_path = buffer.read(cx).project_path(cx)?;
10648            let project = self.project()?.read(cx);
10649            let entry = project.entry_for_path(&project_path, cx)?;
10650            let parent = match &entry.canonical_path {
10651                Some(canonical_path) => canonical_path.to_path_buf(),
10652                None => project.absolute_path(&project_path, cx)?,
10653            }
10654            .parent()?
10655            .to_path_buf();
10656            Some(parent)
10657        }) {
10658            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10659        }
10660    }
10661
10662    fn set_breakpoint_context_menu(
10663        &mut self,
10664        display_row: DisplayRow,
10665        position: Option<Anchor>,
10666        clicked_point: gpui::Point<Pixels>,
10667        window: &mut Window,
10668        cx: &mut Context<Self>,
10669    ) {
10670        let source = self
10671            .buffer
10672            .read(cx)
10673            .snapshot(cx)
10674            .anchor_before(Point::new(display_row.0, 0u32));
10675
10676        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10677
10678        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10679            self,
10680            source,
10681            clicked_point,
10682            context_menu,
10683            window,
10684            cx,
10685        );
10686    }
10687
10688    fn add_edit_breakpoint_block(
10689        &mut self,
10690        anchor: Anchor,
10691        breakpoint: &Breakpoint,
10692        edit_action: BreakpointPromptEditAction,
10693        window: &mut Window,
10694        cx: &mut Context<Self>,
10695    ) {
10696        let weak_editor = cx.weak_entity();
10697        let bp_prompt = cx.new(|cx| {
10698            BreakpointPromptEditor::new(
10699                weak_editor,
10700                anchor,
10701                breakpoint.clone(),
10702                edit_action,
10703                window,
10704                cx,
10705            )
10706        });
10707
10708        let height = bp_prompt.update(cx, |this, cx| {
10709            this.prompt
10710                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10711        });
10712        let cloned_prompt = bp_prompt.clone();
10713        let blocks = vec![BlockProperties {
10714            style: BlockStyle::Sticky,
10715            placement: BlockPlacement::Above(anchor),
10716            height: Some(height),
10717            render: Arc::new(move |cx| {
10718                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10719                cloned_prompt.clone().into_any_element()
10720            }),
10721            priority: 0,
10722        }];
10723
10724        let focus_handle = bp_prompt.focus_handle(cx);
10725        window.focus(&focus_handle);
10726
10727        let block_ids = self.insert_blocks(blocks, None, cx);
10728        bp_prompt.update(cx, |prompt, _| {
10729            prompt.add_block_ids(block_ids);
10730        });
10731    }
10732
10733    pub(crate) fn breakpoint_at_row(
10734        &self,
10735        row: u32,
10736        window: &mut Window,
10737        cx: &mut Context<Self>,
10738    ) -> Option<(Anchor, Breakpoint)> {
10739        let snapshot = self.snapshot(window, cx);
10740        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10741
10742        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10743    }
10744
10745    pub(crate) fn breakpoint_at_anchor(
10746        &self,
10747        breakpoint_position: Anchor,
10748        snapshot: &EditorSnapshot,
10749        cx: &mut Context<Self>,
10750    ) -> Option<(Anchor, Breakpoint)> {
10751        let buffer = self
10752            .buffer
10753            .read(cx)
10754            .buffer_for_anchor(breakpoint_position, cx)?;
10755
10756        let enclosing_excerpt = breakpoint_position.excerpt_id;
10757        let buffer_snapshot = buffer.read(cx).snapshot();
10758
10759        let row = buffer_snapshot
10760            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10761            .row;
10762
10763        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10764        let anchor_end = snapshot
10765            .buffer_snapshot
10766            .anchor_after(Point::new(row, line_len));
10767
10768        self.breakpoint_store
10769            .as_ref()?
10770            .read_with(cx, |breakpoint_store, cx| {
10771                breakpoint_store
10772                    .breakpoints(
10773                        &buffer,
10774                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10775                        &buffer_snapshot,
10776                        cx,
10777                    )
10778                    .next()
10779                    .and_then(|(bp, _)| {
10780                        let breakpoint_row = buffer_snapshot
10781                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10782                            .row;
10783
10784                        if breakpoint_row == row {
10785                            snapshot
10786                                .buffer_snapshot
10787                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10788                                .map(|position| (position, bp.bp.clone()))
10789                        } else {
10790                            None
10791                        }
10792                    })
10793            })
10794    }
10795
10796    pub fn edit_log_breakpoint(
10797        &mut self,
10798        _: &EditLogBreakpoint,
10799        window: &mut Window,
10800        cx: &mut Context<Self>,
10801    ) {
10802        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10803            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10804                message: None,
10805                state: BreakpointState::Enabled,
10806                condition: None,
10807                hit_condition: None,
10808            });
10809
10810            self.add_edit_breakpoint_block(
10811                anchor,
10812                &breakpoint,
10813                BreakpointPromptEditAction::Log,
10814                window,
10815                cx,
10816            );
10817        }
10818    }
10819
10820    fn breakpoints_at_cursors(
10821        &self,
10822        window: &mut Window,
10823        cx: &mut Context<Self>,
10824    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10825        let snapshot = self.snapshot(window, cx);
10826        let cursors = self
10827            .selections
10828            .disjoint_anchors()
10829            .iter()
10830            .map(|selection| {
10831                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10832
10833                let breakpoint_position = self
10834                    .breakpoint_at_row(cursor_position.row, window, cx)
10835                    .map(|bp| bp.0)
10836                    .unwrap_or_else(|| {
10837                        snapshot
10838                            .display_snapshot
10839                            .buffer_snapshot
10840                            .anchor_after(Point::new(cursor_position.row, 0))
10841                    });
10842
10843                let breakpoint = self
10844                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10845                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10846
10847                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10848            })
10849            // 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.
10850            .collect::<HashMap<Anchor, _>>();
10851
10852        cursors.into_iter().collect()
10853    }
10854
10855    pub fn enable_breakpoint(
10856        &mut self,
10857        _: &crate::actions::EnableBreakpoint,
10858        window: &mut Window,
10859        cx: &mut Context<Self>,
10860    ) {
10861        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10862            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10863                continue;
10864            };
10865            self.edit_breakpoint_at_anchor(
10866                anchor,
10867                breakpoint,
10868                BreakpointEditAction::InvertState,
10869                cx,
10870            );
10871        }
10872    }
10873
10874    pub fn disable_breakpoint(
10875        &mut self,
10876        _: &crate::actions::DisableBreakpoint,
10877        window: &mut Window,
10878        cx: &mut Context<Self>,
10879    ) {
10880        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10881            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10882                continue;
10883            };
10884            self.edit_breakpoint_at_anchor(
10885                anchor,
10886                breakpoint,
10887                BreakpointEditAction::InvertState,
10888                cx,
10889            );
10890        }
10891    }
10892
10893    pub fn toggle_breakpoint(
10894        &mut self,
10895        _: &crate::actions::ToggleBreakpoint,
10896        window: &mut Window,
10897        cx: &mut Context<Self>,
10898    ) {
10899        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10900            if let Some(breakpoint) = breakpoint {
10901                self.edit_breakpoint_at_anchor(
10902                    anchor,
10903                    breakpoint,
10904                    BreakpointEditAction::Toggle,
10905                    cx,
10906                );
10907            } else {
10908                self.edit_breakpoint_at_anchor(
10909                    anchor,
10910                    Breakpoint::new_standard(),
10911                    BreakpointEditAction::Toggle,
10912                    cx,
10913                );
10914            }
10915        }
10916    }
10917
10918    pub fn edit_breakpoint_at_anchor(
10919        &mut self,
10920        breakpoint_position: Anchor,
10921        breakpoint: Breakpoint,
10922        edit_action: BreakpointEditAction,
10923        cx: &mut Context<Self>,
10924    ) {
10925        let Some(breakpoint_store) = &self.breakpoint_store else {
10926            return;
10927        };
10928
10929        let Some(buffer) = self
10930            .buffer
10931            .read(cx)
10932            .buffer_for_anchor(breakpoint_position, cx)
10933        else {
10934            return;
10935        };
10936
10937        breakpoint_store.update(cx, |breakpoint_store, cx| {
10938            breakpoint_store.toggle_breakpoint(
10939                buffer,
10940                BreakpointWithPosition {
10941                    position: breakpoint_position.text_anchor,
10942                    bp: breakpoint,
10943                },
10944                edit_action,
10945                cx,
10946            );
10947        });
10948
10949        cx.notify();
10950    }
10951
10952    #[cfg(any(test, feature = "test-support"))]
10953    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10954        self.breakpoint_store.clone()
10955    }
10956
10957    pub fn prepare_restore_change(
10958        &self,
10959        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10960        hunk: &MultiBufferDiffHunk,
10961        cx: &mut App,
10962    ) -> Option<()> {
10963        if hunk.is_created_file() {
10964            return None;
10965        }
10966        let buffer = self.buffer.read(cx);
10967        let diff = buffer.diff_for(hunk.buffer_id)?;
10968        let buffer = buffer.buffer(hunk.buffer_id)?;
10969        let buffer = buffer.read(cx);
10970        let original_text = diff
10971            .read(cx)
10972            .base_text()
10973            .as_rope()
10974            .slice(hunk.diff_base_byte_range.clone());
10975        let buffer_snapshot = buffer.snapshot();
10976        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10977        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10978            probe
10979                .0
10980                .start
10981                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10982                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10983        }) {
10984            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10985            Some(())
10986        } else {
10987            None
10988        }
10989    }
10990
10991    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10992        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10993    }
10994
10995    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10996        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
10997    }
10998
10999    fn manipulate_lines<M>(
11000        &mut self,
11001        window: &mut Window,
11002        cx: &mut Context<Self>,
11003        mut manipulate: M,
11004    ) where
11005        M: FnMut(&str) -> LineManipulationResult,
11006    {
11007        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11008
11009        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11010        let buffer = self.buffer.read(cx).snapshot(cx);
11011
11012        let mut edits = Vec::new();
11013
11014        let selections = self.selections.all::<Point>(cx);
11015        let mut selections = selections.iter().peekable();
11016        let mut contiguous_row_selections = Vec::new();
11017        let mut new_selections = Vec::new();
11018        let mut added_lines = 0;
11019        let mut removed_lines = 0;
11020
11021        while let Some(selection) = selections.next() {
11022            let (start_row, end_row) = consume_contiguous_rows(
11023                &mut contiguous_row_selections,
11024                selection,
11025                &display_map,
11026                &mut selections,
11027            );
11028
11029            let start_point = Point::new(start_row.0, 0);
11030            let end_point = Point::new(
11031                end_row.previous_row().0,
11032                buffer.line_len(end_row.previous_row()),
11033            );
11034            let text = buffer
11035                .text_for_range(start_point..end_point)
11036                .collect::<String>();
11037
11038            let LineManipulationResult {
11039                new_text,
11040                line_count_before,
11041                line_count_after,
11042            } = manipulate(&text);
11043
11044            edits.push((start_point..end_point, new_text));
11045
11046            // Selections must change based on added and removed line count
11047            let start_row =
11048                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11049            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11050            new_selections.push(Selection {
11051                id: selection.id,
11052                start: start_row,
11053                end: end_row,
11054                goal: SelectionGoal::None,
11055                reversed: selection.reversed,
11056            });
11057
11058            if line_count_after > line_count_before {
11059                added_lines += line_count_after - line_count_before;
11060            } else if line_count_before > line_count_after {
11061                removed_lines += line_count_before - line_count_after;
11062            }
11063        }
11064
11065        self.transact(window, cx, |this, window, cx| {
11066            let buffer = this.buffer.update(cx, |buffer, cx| {
11067                buffer.edit(edits, None, cx);
11068                buffer.snapshot(cx)
11069            });
11070
11071            // Recalculate offsets on newly edited buffer
11072            let new_selections = new_selections
11073                .iter()
11074                .map(|s| {
11075                    let start_point = Point::new(s.start.0, 0);
11076                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11077                    Selection {
11078                        id: s.id,
11079                        start: buffer.point_to_offset(start_point),
11080                        end: buffer.point_to_offset(end_point),
11081                        goal: s.goal,
11082                        reversed: s.reversed,
11083                    }
11084                })
11085                .collect();
11086
11087            this.change_selections(Default::default(), window, cx, |s| {
11088                s.select(new_selections);
11089            });
11090
11091            this.request_autoscroll(Autoscroll::fit(), cx);
11092        });
11093    }
11094
11095    fn manipulate_immutable_lines<Fn>(
11096        &mut self,
11097        window: &mut Window,
11098        cx: &mut Context<Self>,
11099        mut callback: Fn,
11100    ) where
11101        Fn: FnMut(&mut Vec<&str>),
11102    {
11103        self.manipulate_lines(window, cx, |text| {
11104            let mut lines: Vec<&str> = text.split('\n').collect();
11105            let line_count_before = lines.len();
11106
11107            callback(&mut lines);
11108
11109            LineManipulationResult {
11110                new_text: lines.join("\n"),
11111                line_count_before,
11112                line_count_after: lines.len(),
11113            }
11114        });
11115    }
11116
11117    fn manipulate_mutable_lines<Fn>(
11118        &mut self,
11119        window: &mut Window,
11120        cx: &mut Context<Self>,
11121        mut callback: Fn,
11122    ) where
11123        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11124    {
11125        self.manipulate_lines(window, cx, |text| {
11126            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11127            let line_count_before = lines.len();
11128
11129            callback(&mut lines);
11130
11131            LineManipulationResult {
11132                new_text: lines.join("\n"),
11133                line_count_before,
11134                line_count_after: lines.len(),
11135            }
11136        });
11137    }
11138
11139    pub fn convert_indentation_to_spaces(
11140        &mut self,
11141        _: &ConvertIndentationToSpaces,
11142        window: &mut Window,
11143        cx: &mut Context<Self>,
11144    ) {
11145        let settings = self.buffer.read(cx).language_settings(cx);
11146        let tab_size = settings.tab_size.get() as usize;
11147
11148        self.manipulate_mutable_lines(window, cx, |lines| {
11149            // Allocates a reasonably sized scratch buffer once for the whole loop
11150            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11151            // Avoids recomputing spaces that could be inserted many times
11152            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11153                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11154                .collect();
11155
11156            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11157                let mut chars = line.as_ref().chars();
11158                let mut col = 0;
11159                let mut changed = false;
11160
11161                for ch in chars.by_ref() {
11162                    match ch {
11163                        ' ' => {
11164                            reindented_line.push(' ');
11165                            col += 1;
11166                        }
11167                        '\t' => {
11168                            // \t are converted to spaces depending on the current column
11169                            let spaces_len = tab_size - (col % tab_size);
11170                            reindented_line.extend(&space_cache[spaces_len - 1]);
11171                            col += spaces_len;
11172                            changed = true;
11173                        }
11174                        _ => {
11175                            // If we dont append before break, the character is consumed
11176                            reindented_line.push(ch);
11177                            break;
11178                        }
11179                    }
11180                }
11181
11182                if !changed {
11183                    reindented_line.clear();
11184                    continue;
11185                }
11186                // Append the rest of the line and replace old reference with new one
11187                reindented_line.extend(chars);
11188                *line = Cow::Owned(reindented_line.clone());
11189                reindented_line.clear();
11190            }
11191        });
11192    }
11193
11194    pub fn convert_indentation_to_tabs(
11195        &mut self,
11196        _: &ConvertIndentationToTabs,
11197        window: &mut Window,
11198        cx: &mut Context<Self>,
11199    ) {
11200        let settings = self.buffer.read(cx).language_settings(cx);
11201        let tab_size = settings.tab_size.get() as usize;
11202
11203        self.manipulate_mutable_lines(window, cx, |lines| {
11204            // Allocates a reasonably sized buffer once for the whole loop
11205            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11206            // Avoids recomputing spaces that could be inserted many times
11207            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11208                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11209                .collect();
11210
11211            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11212                let mut chars = line.chars();
11213                let mut spaces_count = 0;
11214                let mut first_non_indent_char = None;
11215                let mut changed = false;
11216
11217                for ch in chars.by_ref() {
11218                    match ch {
11219                        ' ' => {
11220                            // Keep track of spaces. Append \t when we reach tab_size
11221                            spaces_count += 1;
11222                            changed = true;
11223                            if spaces_count == tab_size {
11224                                reindented_line.push('\t');
11225                                spaces_count = 0;
11226                            }
11227                        }
11228                        '\t' => {
11229                            reindented_line.push('\t');
11230                            spaces_count = 0;
11231                        }
11232                        _ => {
11233                            // Dont append it yet, we might have remaining spaces
11234                            first_non_indent_char = Some(ch);
11235                            break;
11236                        }
11237                    }
11238                }
11239
11240                if !changed {
11241                    reindented_line.clear();
11242                    continue;
11243                }
11244                // Remaining spaces that didn't make a full tab stop
11245                if spaces_count > 0 {
11246                    reindented_line.extend(&space_cache[spaces_count - 1]);
11247                }
11248                // If we consume an extra character that was not indentation, add it back
11249                if let Some(extra_char) = first_non_indent_char {
11250                    reindented_line.push(extra_char);
11251                }
11252                // Append the rest of the line and replace old reference with new one
11253                reindented_line.extend(chars);
11254                *line = Cow::Owned(reindented_line.clone());
11255                reindented_line.clear();
11256            }
11257        });
11258    }
11259
11260    pub fn convert_to_upper_case(
11261        &mut self,
11262        _: &ConvertToUpperCase,
11263        window: &mut Window,
11264        cx: &mut Context<Self>,
11265    ) {
11266        self.manipulate_text(window, cx, |text| text.to_uppercase())
11267    }
11268
11269    pub fn convert_to_lower_case(
11270        &mut self,
11271        _: &ConvertToLowerCase,
11272        window: &mut Window,
11273        cx: &mut Context<Self>,
11274    ) {
11275        self.manipulate_text(window, cx, |text| text.to_lowercase())
11276    }
11277
11278    pub fn convert_to_title_case(
11279        &mut self,
11280        _: &ConvertToTitleCase,
11281        window: &mut Window,
11282        cx: &mut Context<Self>,
11283    ) {
11284        self.manipulate_text(window, cx, |text| {
11285            text.split('\n')
11286                .map(|line| line.to_case(Case::Title))
11287                .join("\n")
11288        })
11289    }
11290
11291    pub fn convert_to_snake_case(
11292        &mut self,
11293        _: &ConvertToSnakeCase,
11294        window: &mut Window,
11295        cx: &mut Context<Self>,
11296    ) {
11297        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11298    }
11299
11300    pub fn convert_to_kebab_case(
11301        &mut self,
11302        _: &ConvertToKebabCase,
11303        window: &mut Window,
11304        cx: &mut Context<Self>,
11305    ) {
11306        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11307    }
11308
11309    pub fn convert_to_upper_camel_case(
11310        &mut self,
11311        _: &ConvertToUpperCamelCase,
11312        window: &mut Window,
11313        cx: &mut Context<Self>,
11314    ) {
11315        self.manipulate_text(window, cx, |text| {
11316            text.split('\n')
11317                .map(|line| line.to_case(Case::UpperCamel))
11318                .join("\n")
11319        })
11320    }
11321
11322    pub fn convert_to_lower_camel_case(
11323        &mut self,
11324        _: &ConvertToLowerCamelCase,
11325        window: &mut Window,
11326        cx: &mut Context<Self>,
11327    ) {
11328        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11329    }
11330
11331    pub fn convert_to_opposite_case(
11332        &mut self,
11333        _: &ConvertToOppositeCase,
11334        window: &mut Window,
11335        cx: &mut Context<Self>,
11336    ) {
11337        self.manipulate_text(window, cx, |text| {
11338            text.chars()
11339                .fold(String::with_capacity(text.len()), |mut t, c| {
11340                    if c.is_uppercase() {
11341                        t.extend(c.to_lowercase());
11342                    } else {
11343                        t.extend(c.to_uppercase());
11344                    }
11345                    t
11346                })
11347        })
11348    }
11349
11350    pub fn convert_to_sentence_case(
11351        &mut self,
11352        _: &ConvertToSentenceCase,
11353        window: &mut Window,
11354        cx: &mut Context<Self>,
11355    ) {
11356        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11357    }
11358
11359    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11360        self.manipulate_text(window, cx, |text| {
11361            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11362            if has_upper_case_characters {
11363                text.to_lowercase()
11364            } else {
11365                text.to_uppercase()
11366            }
11367        })
11368    }
11369
11370    pub fn convert_to_rot13(
11371        &mut self,
11372        _: &ConvertToRot13,
11373        window: &mut Window,
11374        cx: &mut Context<Self>,
11375    ) {
11376        self.manipulate_text(window, cx, |text| {
11377            text.chars()
11378                .map(|c| match c {
11379                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11380                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11381                    _ => c,
11382                })
11383                .collect()
11384        })
11385    }
11386
11387    pub fn convert_to_rot47(
11388        &mut self,
11389        _: &ConvertToRot47,
11390        window: &mut Window,
11391        cx: &mut Context<Self>,
11392    ) {
11393        self.manipulate_text(window, cx, |text| {
11394            text.chars()
11395                .map(|c| {
11396                    let code_point = c as u32;
11397                    if code_point >= 33 && code_point <= 126 {
11398                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11399                    }
11400                    c
11401                })
11402                .collect()
11403        })
11404    }
11405
11406    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11407    where
11408        Fn: FnMut(&str) -> String,
11409    {
11410        let buffer = self.buffer.read(cx).snapshot(cx);
11411
11412        let mut new_selections = Vec::new();
11413        let mut edits = Vec::new();
11414        let mut selection_adjustment = 0i32;
11415
11416        for selection in self.selections.all_adjusted(cx) {
11417            let selection_is_empty = selection.is_empty();
11418
11419            let (start, end) = if selection_is_empty {
11420                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11421                (word_range.start, word_range.end)
11422            } else {
11423                (
11424                    buffer.point_to_offset(selection.start),
11425                    buffer.point_to_offset(selection.end),
11426                )
11427            };
11428
11429            let text = buffer.text_for_range(start..end).collect::<String>();
11430            let old_length = text.len() as i32;
11431            let text = callback(&text);
11432
11433            new_selections.push(Selection {
11434                start: (start as i32 - selection_adjustment) as usize,
11435                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11436                goal: SelectionGoal::None,
11437                id: selection.id,
11438                reversed: selection.reversed,
11439            });
11440
11441            selection_adjustment += old_length - text.len() as i32;
11442
11443            edits.push((start..end, text));
11444        }
11445
11446        self.transact(window, cx, |this, window, cx| {
11447            this.buffer.update(cx, |buffer, cx| {
11448                buffer.edit(edits, None, cx);
11449            });
11450
11451            this.change_selections(Default::default(), window, cx, |s| {
11452                s.select(new_selections);
11453            });
11454
11455            this.request_autoscroll(Autoscroll::fit(), cx);
11456        });
11457    }
11458
11459    pub fn move_selection_on_drop(
11460        &mut self,
11461        selection: &Selection<Anchor>,
11462        target: DisplayPoint,
11463        is_cut: bool,
11464        window: &mut Window,
11465        cx: &mut Context<Self>,
11466    ) {
11467        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11468        let buffer = &display_map.buffer_snapshot;
11469        let mut edits = Vec::new();
11470        let insert_point = display_map
11471            .clip_point(target, Bias::Left)
11472            .to_point(&display_map);
11473        let text = buffer
11474            .text_for_range(selection.start..selection.end)
11475            .collect::<String>();
11476        if is_cut {
11477            edits.push(((selection.start..selection.end), String::new()));
11478        }
11479        let insert_anchor = buffer.anchor_before(insert_point);
11480        edits.push(((insert_anchor..insert_anchor), text));
11481        let last_edit_start = insert_anchor.bias_left(buffer);
11482        let last_edit_end = insert_anchor.bias_right(buffer);
11483        self.transact(window, cx, |this, window, cx| {
11484            this.buffer.update(cx, |buffer, cx| {
11485                buffer.edit(edits, None, cx);
11486            });
11487            this.change_selections(Default::default(), window, cx, |s| {
11488                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11489            });
11490        });
11491    }
11492
11493    pub fn clear_selection_drag_state(&mut self) {
11494        self.selection_drag_state = SelectionDragState::None;
11495    }
11496
11497    pub fn duplicate(
11498        &mut self,
11499        upwards: bool,
11500        whole_lines: bool,
11501        window: &mut Window,
11502        cx: &mut Context<Self>,
11503    ) {
11504        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11505
11506        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11507        let buffer = &display_map.buffer_snapshot;
11508        let selections = self.selections.all::<Point>(cx);
11509
11510        let mut edits = Vec::new();
11511        let mut selections_iter = selections.iter().peekable();
11512        while let Some(selection) = selections_iter.next() {
11513            let mut rows = selection.spanned_rows(false, &display_map);
11514            // duplicate line-wise
11515            if whole_lines || selection.start == selection.end {
11516                // Avoid duplicating the same lines twice.
11517                while let Some(next_selection) = selections_iter.peek() {
11518                    let next_rows = next_selection.spanned_rows(false, &display_map);
11519                    if next_rows.start < rows.end {
11520                        rows.end = next_rows.end;
11521                        selections_iter.next().unwrap();
11522                    } else {
11523                        break;
11524                    }
11525                }
11526
11527                // Copy the text from the selected row region and splice it either at the start
11528                // or end of the region.
11529                let start = Point::new(rows.start.0, 0);
11530                let end = Point::new(
11531                    rows.end.previous_row().0,
11532                    buffer.line_len(rows.end.previous_row()),
11533                );
11534                let text = buffer
11535                    .text_for_range(start..end)
11536                    .chain(Some("\n"))
11537                    .collect::<String>();
11538                let insert_location = if upwards {
11539                    Point::new(rows.end.0, 0)
11540                } else {
11541                    start
11542                };
11543                edits.push((insert_location..insert_location, text));
11544            } else {
11545                // duplicate character-wise
11546                let start = selection.start;
11547                let end = selection.end;
11548                let text = buffer.text_for_range(start..end).collect::<String>();
11549                edits.push((selection.end..selection.end, text));
11550            }
11551        }
11552
11553        self.transact(window, cx, |this, _, cx| {
11554            this.buffer.update(cx, |buffer, cx| {
11555                buffer.edit(edits, None, cx);
11556            });
11557
11558            this.request_autoscroll(Autoscroll::fit(), cx);
11559        });
11560    }
11561
11562    pub fn duplicate_line_up(
11563        &mut self,
11564        _: &DuplicateLineUp,
11565        window: &mut Window,
11566        cx: &mut Context<Self>,
11567    ) {
11568        self.duplicate(true, true, window, cx);
11569    }
11570
11571    pub fn duplicate_line_down(
11572        &mut self,
11573        _: &DuplicateLineDown,
11574        window: &mut Window,
11575        cx: &mut Context<Self>,
11576    ) {
11577        self.duplicate(false, true, window, cx);
11578    }
11579
11580    pub fn duplicate_selection(
11581        &mut self,
11582        _: &DuplicateSelection,
11583        window: &mut Window,
11584        cx: &mut Context<Self>,
11585    ) {
11586        self.duplicate(false, false, window, cx);
11587    }
11588
11589    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11590        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11591        if self.mode.is_single_line() {
11592            cx.propagate();
11593            return;
11594        }
11595
11596        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11597        let buffer = self.buffer.read(cx).snapshot(cx);
11598
11599        let mut edits = Vec::new();
11600        let mut unfold_ranges = Vec::new();
11601        let mut refold_creases = Vec::new();
11602
11603        let selections = self.selections.all::<Point>(cx);
11604        let mut selections = selections.iter().peekable();
11605        let mut contiguous_row_selections = Vec::new();
11606        let mut new_selections = Vec::new();
11607
11608        while let Some(selection) = selections.next() {
11609            // Find all the selections that span a contiguous row range
11610            let (start_row, end_row) = consume_contiguous_rows(
11611                &mut contiguous_row_selections,
11612                selection,
11613                &display_map,
11614                &mut selections,
11615            );
11616
11617            // Move the text spanned by the row range to be before the line preceding the row range
11618            if start_row.0 > 0 {
11619                let range_to_move = Point::new(
11620                    start_row.previous_row().0,
11621                    buffer.line_len(start_row.previous_row()),
11622                )
11623                    ..Point::new(
11624                        end_row.previous_row().0,
11625                        buffer.line_len(end_row.previous_row()),
11626                    );
11627                let insertion_point = display_map
11628                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11629                    .0;
11630
11631                // Don't move lines across excerpts
11632                if buffer
11633                    .excerpt_containing(insertion_point..range_to_move.end)
11634                    .is_some()
11635                {
11636                    let text = buffer
11637                        .text_for_range(range_to_move.clone())
11638                        .flat_map(|s| s.chars())
11639                        .skip(1)
11640                        .chain(['\n'])
11641                        .collect::<String>();
11642
11643                    edits.push((
11644                        buffer.anchor_after(range_to_move.start)
11645                            ..buffer.anchor_before(range_to_move.end),
11646                        String::new(),
11647                    ));
11648                    let insertion_anchor = buffer.anchor_after(insertion_point);
11649                    edits.push((insertion_anchor..insertion_anchor, text));
11650
11651                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11652
11653                    // Move selections up
11654                    new_selections.extend(contiguous_row_selections.drain(..).map(
11655                        |mut selection| {
11656                            selection.start.row -= row_delta;
11657                            selection.end.row -= row_delta;
11658                            selection
11659                        },
11660                    ));
11661
11662                    // Move folds up
11663                    unfold_ranges.push(range_to_move.clone());
11664                    for fold in display_map.folds_in_range(
11665                        buffer.anchor_before(range_to_move.start)
11666                            ..buffer.anchor_after(range_to_move.end),
11667                    ) {
11668                        let mut start = fold.range.start.to_point(&buffer);
11669                        let mut end = fold.range.end.to_point(&buffer);
11670                        start.row -= row_delta;
11671                        end.row -= row_delta;
11672                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11673                    }
11674                }
11675            }
11676
11677            // If we didn't move line(s), preserve the existing selections
11678            new_selections.append(&mut contiguous_row_selections);
11679        }
11680
11681        self.transact(window, cx, |this, window, cx| {
11682            this.unfold_ranges(&unfold_ranges, true, true, cx);
11683            this.buffer.update(cx, |buffer, cx| {
11684                for (range, text) in edits {
11685                    buffer.edit([(range, text)], None, cx);
11686                }
11687            });
11688            this.fold_creases(refold_creases, true, window, cx);
11689            this.change_selections(Default::default(), window, cx, |s| {
11690                s.select(new_selections);
11691            })
11692        });
11693    }
11694
11695    pub fn move_line_down(
11696        &mut self,
11697        _: &MoveLineDown,
11698        window: &mut Window,
11699        cx: &mut Context<Self>,
11700    ) {
11701        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11702        if self.mode.is_single_line() {
11703            cx.propagate();
11704            return;
11705        }
11706
11707        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11708        let buffer = self.buffer.read(cx).snapshot(cx);
11709
11710        let mut edits = Vec::new();
11711        let mut unfold_ranges = Vec::new();
11712        let mut refold_creases = Vec::new();
11713
11714        let selections = self.selections.all::<Point>(cx);
11715        let mut selections = selections.iter().peekable();
11716        let mut contiguous_row_selections = Vec::new();
11717        let mut new_selections = Vec::new();
11718
11719        while let Some(selection) = selections.next() {
11720            // Find all the selections that span a contiguous row range
11721            let (start_row, end_row) = consume_contiguous_rows(
11722                &mut contiguous_row_selections,
11723                selection,
11724                &display_map,
11725                &mut selections,
11726            );
11727
11728            // Move the text spanned by the row range to be after the last line of the row range
11729            if end_row.0 <= buffer.max_point().row {
11730                let range_to_move =
11731                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11732                let insertion_point = display_map
11733                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11734                    .0;
11735
11736                // Don't move lines across excerpt boundaries
11737                if buffer
11738                    .excerpt_containing(range_to_move.start..insertion_point)
11739                    .is_some()
11740                {
11741                    let mut text = String::from("\n");
11742                    text.extend(buffer.text_for_range(range_to_move.clone()));
11743                    text.pop(); // Drop trailing newline
11744                    edits.push((
11745                        buffer.anchor_after(range_to_move.start)
11746                            ..buffer.anchor_before(range_to_move.end),
11747                        String::new(),
11748                    ));
11749                    let insertion_anchor = buffer.anchor_after(insertion_point);
11750                    edits.push((insertion_anchor..insertion_anchor, text));
11751
11752                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11753
11754                    // Move selections down
11755                    new_selections.extend(contiguous_row_selections.drain(..).map(
11756                        |mut selection| {
11757                            selection.start.row += row_delta;
11758                            selection.end.row += row_delta;
11759                            selection
11760                        },
11761                    ));
11762
11763                    // Move folds down
11764                    unfold_ranges.push(range_to_move.clone());
11765                    for fold in display_map.folds_in_range(
11766                        buffer.anchor_before(range_to_move.start)
11767                            ..buffer.anchor_after(range_to_move.end),
11768                    ) {
11769                        let mut start = fold.range.start.to_point(&buffer);
11770                        let mut end = fold.range.end.to_point(&buffer);
11771                        start.row += row_delta;
11772                        end.row += row_delta;
11773                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11774                    }
11775                }
11776            }
11777
11778            // If we didn't move line(s), preserve the existing selections
11779            new_selections.append(&mut contiguous_row_selections);
11780        }
11781
11782        self.transact(window, cx, |this, window, cx| {
11783            this.unfold_ranges(&unfold_ranges, true, true, cx);
11784            this.buffer.update(cx, |buffer, cx| {
11785                for (range, text) in edits {
11786                    buffer.edit([(range, text)], None, cx);
11787                }
11788            });
11789            this.fold_creases(refold_creases, true, window, cx);
11790            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11791        });
11792    }
11793
11794    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11795        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11796        let text_layout_details = &self.text_layout_details(window);
11797        self.transact(window, cx, |this, window, cx| {
11798            let edits = this.change_selections(Default::default(), window, cx, |s| {
11799                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11800                s.move_with(|display_map, selection| {
11801                    if !selection.is_empty() {
11802                        return;
11803                    }
11804
11805                    let mut head = selection.head();
11806                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11807                    if head.column() == display_map.line_len(head.row()) {
11808                        transpose_offset = display_map
11809                            .buffer_snapshot
11810                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11811                    }
11812
11813                    if transpose_offset == 0 {
11814                        return;
11815                    }
11816
11817                    *head.column_mut() += 1;
11818                    head = display_map.clip_point(head, Bias::Right);
11819                    let goal = SelectionGoal::HorizontalPosition(
11820                        display_map
11821                            .x_for_display_point(head, text_layout_details)
11822                            .into(),
11823                    );
11824                    selection.collapse_to(head, goal);
11825
11826                    let transpose_start = display_map
11827                        .buffer_snapshot
11828                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11829                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11830                        let transpose_end = display_map
11831                            .buffer_snapshot
11832                            .clip_offset(transpose_offset + 1, Bias::Right);
11833                        if let Some(ch) =
11834                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11835                        {
11836                            edits.push((transpose_start..transpose_offset, String::new()));
11837                            edits.push((transpose_end..transpose_end, ch.to_string()));
11838                        }
11839                    }
11840                });
11841                edits
11842            });
11843            this.buffer
11844                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11845            let selections = this.selections.all::<usize>(cx);
11846            this.change_selections(Default::default(), window, cx, |s| {
11847                s.select(selections);
11848            });
11849        });
11850    }
11851
11852    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11853        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11854        if self.mode.is_single_line() {
11855            cx.propagate();
11856            return;
11857        }
11858
11859        self.rewrap_impl(RewrapOptions::default(), cx)
11860    }
11861
11862    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11863        let buffer = self.buffer.read(cx).snapshot(cx);
11864        let selections = self.selections.all::<Point>(cx);
11865
11866        #[derive(Clone, Debug, PartialEq)]
11867        enum CommentFormat {
11868            /// single line comment, with prefix for line
11869            Line(String),
11870            /// single line within a block comment, with prefix for line
11871            BlockLine(String),
11872            /// a single line of a block comment that includes the initial delimiter
11873            BlockCommentWithStart(BlockCommentConfig),
11874            /// a single line of a block comment that includes the ending delimiter
11875            BlockCommentWithEnd(BlockCommentConfig),
11876        }
11877
11878        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11879        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11880            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11881                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11882                .peekable();
11883
11884            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11885                row
11886            } else {
11887                return Vec::new();
11888            };
11889
11890            let language_settings = buffer.language_settings_at(selection.head(), cx);
11891            let language_scope = buffer.language_scope_at(selection.head());
11892
11893            let indent_and_prefix_for_row =
11894                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11895                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11896                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11897                        &language_scope
11898                    {
11899                        let indent_end = Point::new(row, indent.len);
11900                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11901                        let line_text_after_indent = buffer
11902                            .text_for_range(indent_end..line_end)
11903                            .collect::<String>();
11904
11905                        let is_within_comment_override = buffer
11906                            .language_scope_at(indent_end)
11907                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11908                        let comment_delimiters = if is_within_comment_override {
11909                            // we are within a comment syntax node, but we don't
11910                            // yet know what kind of comment: block, doc or line
11911                            match (
11912                                language_scope.documentation_comment(),
11913                                language_scope.block_comment(),
11914                            ) {
11915                                (Some(config), _) | (_, Some(config))
11916                                    if buffer.contains_str_at(indent_end, &config.start) =>
11917                                {
11918                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11919                                }
11920                                (Some(config), _) | (_, Some(config))
11921                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11922                                {
11923                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11924                                }
11925                                (Some(config), _) | (_, Some(config))
11926                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11927                                {
11928                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11929                                }
11930                                (_, _) => language_scope
11931                                    .line_comment_prefixes()
11932                                    .iter()
11933                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11934                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11935                            }
11936                        } else {
11937                            // we not in an overridden comment node, but we may
11938                            // be within a non-overridden line comment node
11939                            language_scope
11940                                .line_comment_prefixes()
11941                                .iter()
11942                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11943                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11944                        };
11945
11946                        let rewrap_prefix = language_scope
11947                            .rewrap_prefixes()
11948                            .iter()
11949                            .find_map(|prefix_regex| {
11950                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11951                                    if mat.start() == 0 {
11952                                        Some(mat.as_str().to_string())
11953                                    } else {
11954                                        None
11955                                    }
11956                                })
11957                            })
11958                            .flatten();
11959                        (comment_delimiters, rewrap_prefix)
11960                    } else {
11961                        (None, None)
11962                    };
11963                    (indent, comment_prefix, rewrap_prefix)
11964                };
11965
11966            let mut ranges = Vec::new();
11967            let from_empty_selection = selection.is_empty();
11968
11969            let mut current_range_start = first_row;
11970            let mut prev_row = first_row;
11971            let (
11972                mut current_range_indent,
11973                mut current_range_comment_delimiters,
11974                mut current_range_rewrap_prefix,
11975            ) = indent_and_prefix_for_row(first_row);
11976
11977            for row in non_blank_rows_iter.skip(1) {
11978                let has_paragraph_break = row > prev_row + 1;
11979
11980                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
11981                    indent_and_prefix_for_row(row);
11982
11983                let has_indent_change = row_indent != current_range_indent;
11984                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
11985
11986                let has_boundary_change = has_comment_change
11987                    || row_rewrap_prefix.is_some()
11988                    || (has_indent_change && current_range_comment_delimiters.is_some());
11989
11990                if has_paragraph_break || has_boundary_change {
11991                    ranges.push((
11992                        language_settings.clone(),
11993                        Point::new(current_range_start, 0)
11994                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11995                        current_range_indent,
11996                        current_range_comment_delimiters.clone(),
11997                        current_range_rewrap_prefix.clone(),
11998                        from_empty_selection,
11999                    ));
12000                    current_range_start = row;
12001                    current_range_indent = row_indent;
12002                    current_range_comment_delimiters = row_comment_delimiters;
12003                    current_range_rewrap_prefix = row_rewrap_prefix;
12004                }
12005                prev_row = row;
12006            }
12007
12008            ranges.push((
12009                language_settings.clone(),
12010                Point::new(current_range_start, 0)
12011                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12012                current_range_indent,
12013                current_range_comment_delimiters,
12014                current_range_rewrap_prefix,
12015                from_empty_selection,
12016            ));
12017
12018            ranges
12019        });
12020
12021        let mut edits = Vec::new();
12022        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12023
12024        for (
12025            language_settings,
12026            wrap_range,
12027            mut indent_size,
12028            comment_prefix,
12029            rewrap_prefix,
12030            from_empty_selection,
12031        ) in wrap_ranges
12032        {
12033            let mut start_row = wrap_range.start.row;
12034            let mut end_row = wrap_range.end.row;
12035
12036            // Skip selections that overlap with a range that has already been rewrapped.
12037            let selection_range = start_row..end_row;
12038            if rewrapped_row_ranges
12039                .iter()
12040                .any(|range| range.overlaps(&selection_range))
12041            {
12042                continue;
12043            }
12044
12045            let tab_size = language_settings.tab_size;
12046
12047            let (line_prefix, inside_comment) = match &comment_prefix {
12048                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12049                    (Some(prefix.as_str()), true)
12050                }
12051                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12052                    (Some(prefix.as_ref()), true)
12053                }
12054                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12055                    start: _,
12056                    end: _,
12057                    prefix,
12058                    tab_size,
12059                })) => {
12060                    indent_size.len += tab_size;
12061                    (Some(prefix.as_ref()), true)
12062                }
12063                None => (None, false),
12064            };
12065            let indent_prefix = indent_size.chars().collect::<String>();
12066            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12067
12068            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12069                RewrapBehavior::InComments => inside_comment,
12070                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12071                RewrapBehavior::Anywhere => true,
12072            };
12073
12074            let should_rewrap = options.override_language_settings
12075                || allow_rewrap_based_on_language
12076                || self.hard_wrap.is_some();
12077            if !should_rewrap {
12078                continue;
12079            }
12080
12081            if from_empty_selection {
12082                'expand_upwards: while start_row > 0 {
12083                    let prev_row = start_row - 1;
12084                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12085                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12086                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12087                    {
12088                        start_row = prev_row;
12089                    } else {
12090                        break 'expand_upwards;
12091                    }
12092                }
12093
12094                'expand_downwards: while end_row < buffer.max_point().row {
12095                    let next_row = end_row + 1;
12096                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12097                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12098                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12099                    {
12100                        end_row = next_row;
12101                    } else {
12102                        break 'expand_downwards;
12103                    }
12104                }
12105            }
12106
12107            let start = Point::new(start_row, 0);
12108            let start_offset = start.to_offset(&buffer);
12109            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12110            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12111            let mut first_line_delimiter = None;
12112            let mut last_line_delimiter = None;
12113            let Some(lines_without_prefixes) = selection_text
12114                .lines()
12115                .enumerate()
12116                .map(|(ix, line)| {
12117                    let line_trimmed = line.trim_start();
12118                    if rewrap_prefix.is_some() && ix > 0 {
12119                        Ok(line_trimmed)
12120                    } else if let Some(
12121                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12122                            start,
12123                            prefix,
12124                            end,
12125                            tab_size,
12126                        })
12127                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12128                            start,
12129                            prefix,
12130                            end,
12131                            tab_size,
12132                        }),
12133                    ) = &comment_prefix
12134                    {
12135                        let line_trimmed = line_trimmed
12136                            .strip_prefix(start.as_ref())
12137                            .map(|s| {
12138                                let mut indent_size = indent_size;
12139                                indent_size.len -= tab_size;
12140                                let indent_prefix: String = indent_size.chars().collect();
12141                                first_line_delimiter = Some((indent_prefix, start));
12142                                s.trim_start()
12143                            })
12144                            .unwrap_or(line_trimmed);
12145                        let line_trimmed = line_trimmed
12146                            .strip_suffix(end.as_ref())
12147                            .map(|s| {
12148                                last_line_delimiter = Some(end);
12149                                s.trim_end()
12150                            })
12151                            .unwrap_or(line_trimmed);
12152                        let line_trimmed = line_trimmed
12153                            .strip_prefix(prefix.as_ref())
12154                            .unwrap_or(line_trimmed);
12155                        Ok(line_trimmed)
12156                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12157                        line_trimmed.strip_prefix(prefix).with_context(|| {
12158                            format!("line did not start with prefix {prefix:?}: {line:?}")
12159                        })
12160                    } else {
12161                        line_trimmed
12162                            .strip_prefix(&line_prefix.trim_start())
12163                            .with_context(|| {
12164                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12165                            })
12166                    }
12167                })
12168                .collect::<Result<Vec<_>, _>>()
12169                .log_err()
12170            else {
12171                continue;
12172            };
12173
12174            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12175                buffer
12176                    .language_settings_at(Point::new(start_row, 0), cx)
12177                    .preferred_line_length as usize
12178            });
12179
12180            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12181                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12182            } else {
12183                line_prefix.clone()
12184            };
12185
12186            let wrapped_text = {
12187                let mut wrapped_text = wrap_with_prefix(
12188                    line_prefix,
12189                    subsequent_lines_prefix,
12190                    lines_without_prefixes.join("\n"),
12191                    wrap_column,
12192                    tab_size,
12193                    options.preserve_existing_whitespace,
12194                );
12195
12196                if let Some((indent, delimiter)) = first_line_delimiter {
12197                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12198                }
12199                if let Some(last_line) = last_line_delimiter {
12200                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12201                }
12202
12203                wrapped_text
12204            };
12205
12206            // TODO: should always use char-based diff while still supporting cursor behavior that
12207            // matches vim.
12208            let mut diff_options = DiffOptions::default();
12209            if options.override_language_settings {
12210                diff_options.max_word_diff_len = 0;
12211                diff_options.max_word_diff_line_count = 0;
12212            } else {
12213                diff_options.max_word_diff_len = usize::MAX;
12214                diff_options.max_word_diff_line_count = usize::MAX;
12215            }
12216
12217            for (old_range, new_text) in
12218                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12219            {
12220                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12221                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12222                edits.push((edit_start..edit_end, new_text));
12223            }
12224
12225            rewrapped_row_ranges.push(start_row..=end_row);
12226        }
12227
12228        self.buffer
12229            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12230    }
12231
12232    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
12233        let mut text = String::new();
12234        let buffer = self.buffer.read(cx).snapshot(cx);
12235        let mut selections = self.selections.all::<Point>(cx);
12236        let mut clipboard_selections = Vec::with_capacity(selections.len());
12237        {
12238            let max_point = buffer.max_point();
12239            let mut is_first = true;
12240            for selection in &mut selections {
12241                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12242                if is_entire_line {
12243                    selection.start = Point::new(selection.start.row, 0);
12244                    if !selection.is_empty() && selection.end.column == 0 {
12245                        selection.end = cmp::min(max_point, selection.end);
12246                    } else {
12247                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12248                    }
12249                    selection.goal = SelectionGoal::None;
12250                }
12251                if is_first {
12252                    is_first = false;
12253                } else {
12254                    text += "\n";
12255                }
12256                let mut len = 0;
12257                for chunk in buffer.text_for_range(selection.start..selection.end) {
12258                    text.push_str(chunk);
12259                    len += chunk.len();
12260                }
12261                clipboard_selections.push(ClipboardSelection {
12262                    len,
12263                    is_entire_line,
12264                    first_line_indent: buffer
12265                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12266                        .len,
12267                });
12268            }
12269        }
12270
12271        self.transact(window, cx, |this, window, cx| {
12272            this.change_selections(Default::default(), window, cx, |s| {
12273                s.select(selections);
12274            });
12275            this.insert("", window, cx);
12276        });
12277        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12278    }
12279
12280    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12281        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12282        let item = self.cut_common(window, cx);
12283        cx.write_to_clipboard(item);
12284    }
12285
12286    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12287        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12288        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12289            s.move_with(|snapshot, sel| {
12290                if sel.is_empty() {
12291                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12292                }
12293            });
12294        });
12295        let item = self.cut_common(window, cx);
12296        cx.set_global(KillRing(item))
12297    }
12298
12299    pub fn kill_ring_yank(
12300        &mut self,
12301        _: &KillRingYank,
12302        window: &mut Window,
12303        cx: &mut Context<Self>,
12304    ) {
12305        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12306        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12307            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12308                (kill_ring.text().to_string(), kill_ring.metadata_json())
12309            } else {
12310                return;
12311            }
12312        } else {
12313            return;
12314        };
12315        self.do_paste(&text, metadata, false, window, cx);
12316    }
12317
12318    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12319        self.do_copy(true, cx);
12320    }
12321
12322    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12323        self.do_copy(false, cx);
12324    }
12325
12326    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12327        let selections = self.selections.all::<Point>(cx);
12328        let buffer = self.buffer.read(cx).read(cx);
12329        let mut text = String::new();
12330
12331        let mut clipboard_selections = Vec::with_capacity(selections.len());
12332        {
12333            let max_point = buffer.max_point();
12334            let mut is_first = true;
12335            for selection in &selections {
12336                let mut start = selection.start;
12337                let mut end = selection.end;
12338                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12339                if is_entire_line {
12340                    start = Point::new(start.row, 0);
12341                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12342                }
12343
12344                let mut trimmed_selections = Vec::new();
12345                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12346                    let row = MultiBufferRow(start.row);
12347                    let first_indent = buffer.indent_size_for_line(row);
12348                    if first_indent.len == 0 || start.column > first_indent.len {
12349                        trimmed_selections.push(start..end);
12350                    } else {
12351                        trimmed_selections.push(
12352                            Point::new(row.0, first_indent.len)
12353                                ..Point::new(row.0, buffer.line_len(row)),
12354                        );
12355                        for row in start.row + 1..=end.row {
12356                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12357                            if row == end.row {
12358                                line_len = end.column;
12359                            }
12360                            if line_len == 0 {
12361                                trimmed_selections
12362                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12363                                continue;
12364                            }
12365                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12366                            if row_indent_size.len >= first_indent.len {
12367                                trimmed_selections.push(
12368                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12369                                );
12370                            } else {
12371                                trimmed_selections.clear();
12372                                trimmed_selections.push(start..end);
12373                                break;
12374                            }
12375                        }
12376                    }
12377                } else {
12378                    trimmed_selections.push(start..end);
12379                }
12380
12381                for trimmed_range in trimmed_selections {
12382                    if is_first {
12383                        is_first = false;
12384                    } else {
12385                        text += "\n";
12386                    }
12387                    let mut len = 0;
12388                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12389                        text.push_str(chunk);
12390                        len += chunk.len();
12391                    }
12392                    clipboard_selections.push(ClipboardSelection {
12393                        len,
12394                        is_entire_line,
12395                        first_line_indent: buffer
12396                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12397                            .len,
12398                    });
12399                }
12400            }
12401        }
12402
12403        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12404            text,
12405            clipboard_selections,
12406        ));
12407    }
12408
12409    pub fn do_paste(
12410        &mut self,
12411        text: &String,
12412        clipboard_selections: Option<Vec<ClipboardSelection>>,
12413        handle_entire_lines: bool,
12414        window: &mut Window,
12415        cx: &mut Context<Self>,
12416    ) {
12417        if self.read_only(cx) {
12418            return;
12419        }
12420
12421        let clipboard_text = Cow::Borrowed(text);
12422
12423        self.transact(window, cx, |this, window, cx| {
12424            let had_active_edit_prediction = this.has_active_edit_prediction();
12425
12426            if let Some(mut clipboard_selections) = clipboard_selections {
12427                let old_selections = this.selections.all::<usize>(cx);
12428                let all_selections_were_entire_line =
12429                    clipboard_selections.iter().all(|s| s.is_entire_line);
12430                let first_selection_indent_column =
12431                    clipboard_selections.first().map(|s| s.first_line_indent);
12432                if clipboard_selections.len() != old_selections.len() {
12433                    clipboard_selections.drain(..);
12434                }
12435                let cursor_offset = this.selections.last::<usize>(cx).head();
12436                let mut auto_indent_on_paste = true;
12437
12438                this.buffer.update(cx, |buffer, cx| {
12439                    let snapshot = buffer.read(cx);
12440                    auto_indent_on_paste = snapshot
12441                        .language_settings_at(cursor_offset, cx)
12442                        .auto_indent_on_paste;
12443
12444                    let mut start_offset = 0;
12445                    let mut edits = Vec::new();
12446                    let mut original_indent_columns = Vec::new();
12447                    for (ix, selection) in old_selections.iter().enumerate() {
12448                        let to_insert;
12449                        let entire_line;
12450                        let original_indent_column;
12451                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12452                            let end_offset = start_offset + clipboard_selection.len;
12453                            to_insert = &clipboard_text[start_offset..end_offset];
12454                            entire_line = clipboard_selection.is_entire_line;
12455                            start_offset = end_offset + 1;
12456                            original_indent_column = Some(clipboard_selection.first_line_indent);
12457                        } else {
12458                            to_insert = clipboard_text.as_str();
12459                            entire_line = all_selections_were_entire_line;
12460                            original_indent_column = first_selection_indent_column
12461                        }
12462
12463                        // If the corresponding selection was empty when this slice of the
12464                        // clipboard text was written, then the entire line containing the
12465                        // selection was copied. If this selection is also currently empty,
12466                        // then paste the line before the current line of the buffer.
12467                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12468                            let column = selection.start.to_point(&snapshot).column as usize;
12469                            let line_start = selection.start - column;
12470                            line_start..line_start
12471                        } else {
12472                            selection.range()
12473                        };
12474
12475                        edits.push((range, to_insert));
12476                        original_indent_columns.push(original_indent_column);
12477                    }
12478                    drop(snapshot);
12479
12480                    buffer.edit(
12481                        edits,
12482                        if auto_indent_on_paste {
12483                            Some(AutoindentMode::Block {
12484                                original_indent_columns,
12485                            })
12486                        } else {
12487                            None
12488                        },
12489                        cx,
12490                    );
12491                });
12492
12493                let selections = this.selections.all::<usize>(cx);
12494                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12495            } else {
12496                this.insert(&clipboard_text, window, cx);
12497            }
12498
12499            let trigger_in_words =
12500                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12501
12502            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12503        });
12504    }
12505
12506    pub fn diff_clipboard_with_selection(
12507        &mut self,
12508        _: &DiffClipboardWithSelection,
12509        window: &mut Window,
12510        cx: &mut Context<Self>,
12511    ) {
12512        let selections = self.selections.all::<usize>(cx);
12513
12514        if selections.is_empty() {
12515            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12516            return;
12517        };
12518
12519        let clipboard_text = match cx.read_from_clipboard() {
12520            Some(item) => match item.entries().first() {
12521                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12522                _ => None,
12523            },
12524            None => None,
12525        };
12526
12527        let Some(clipboard_text) = clipboard_text else {
12528            log::warn!("Clipboard doesn't contain text.");
12529            return;
12530        };
12531
12532        window.dispatch_action(
12533            Box::new(DiffClipboardWithSelectionData {
12534                clipboard_text,
12535                editor: cx.entity(),
12536            }),
12537            cx,
12538        );
12539    }
12540
12541    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12542        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12543        if let Some(item) = cx.read_from_clipboard() {
12544            let entries = item.entries();
12545
12546            match entries.first() {
12547                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12548                // of all the pasted entries.
12549                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12550                    .do_paste(
12551                        clipboard_string.text(),
12552                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12553                        true,
12554                        window,
12555                        cx,
12556                    ),
12557                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12558            }
12559        }
12560    }
12561
12562    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12563        if self.read_only(cx) {
12564            return;
12565        }
12566
12567        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12568
12569        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12570            if let Some((selections, _)) =
12571                self.selection_history.transaction(transaction_id).cloned()
12572            {
12573                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12574                    s.select_anchors(selections.to_vec());
12575                });
12576            } else {
12577                log::error!(
12578                    "No entry in selection_history found for undo. \
12579                     This may correspond to a bug where undo does not update the selection. \
12580                     If this is occurring, please add details to \
12581                     https://github.com/zed-industries/zed/issues/22692"
12582                );
12583            }
12584            self.request_autoscroll(Autoscroll::fit(), cx);
12585            self.unmark_text(window, cx);
12586            self.refresh_edit_prediction(true, false, window, cx);
12587            cx.emit(EditorEvent::Edited { transaction_id });
12588            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12589        }
12590    }
12591
12592    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12593        if self.read_only(cx) {
12594            return;
12595        }
12596
12597        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12598
12599        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12600            if let Some((_, Some(selections))) =
12601                self.selection_history.transaction(transaction_id).cloned()
12602            {
12603                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12604                    s.select_anchors(selections.to_vec());
12605                });
12606            } else {
12607                log::error!(
12608                    "No entry in selection_history found for redo. \
12609                     This may correspond to a bug where undo does not update the selection. \
12610                     If this is occurring, please add details to \
12611                     https://github.com/zed-industries/zed/issues/22692"
12612                );
12613            }
12614            self.request_autoscroll(Autoscroll::fit(), cx);
12615            self.unmark_text(window, cx);
12616            self.refresh_edit_prediction(true, false, window, cx);
12617            cx.emit(EditorEvent::Edited { transaction_id });
12618        }
12619    }
12620
12621    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12622        self.buffer
12623            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12624    }
12625
12626    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12627        self.buffer
12628            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12629    }
12630
12631    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12632        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12633        self.change_selections(Default::default(), window, cx, |s| {
12634            s.move_with(|map, selection| {
12635                let cursor = if selection.is_empty() {
12636                    movement::left(map, selection.start)
12637                } else {
12638                    selection.start
12639                };
12640                selection.collapse_to(cursor, SelectionGoal::None);
12641            });
12642        })
12643    }
12644
12645    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12646        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12647        self.change_selections(Default::default(), window, cx, |s| {
12648            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12649        })
12650    }
12651
12652    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12653        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12654        self.change_selections(Default::default(), window, cx, |s| {
12655            s.move_with(|map, selection| {
12656                let cursor = if selection.is_empty() {
12657                    movement::right(map, selection.end)
12658                } else {
12659                    selection.end
12660                };
12661                selection.collapse_to(cursor, SelectionGoal::None)
12662            });
12663        })
12664    }
12665
12666    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12667        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12668        self.change_selections(Default::default(), window, cx, |s| {
12669            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12670        })
12671    }
12672
12673    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12674        if self.take_rename(true, window, cx).is_some() {
12675            return;
12676        }
12677
12678        if self.mode.is_single_line() {
12679            cx.propagate();
12680            return;
12681        }
12682
12683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12684
12685        let text_layout_details = &self.text_layout_details(window);
12686        let selection_count = self.selections.count();
12687        let first_selection = self.selections.first_anchor();
12688
12689        self.change_selections(Default::default(), window, cx, |s| {
12690            s.move_with(|map, selection| {
12691                if !selection.is_empty() {
12692                    selection.goal = SelectionGoal::None;
12693                }
12694                let (cursor, goal) = movement::up(
12695                    map,
12696                    selection.start,
12697                    selection.goal,
12698                    false,
12699                    text_layout_details,
12700                );
12701                selection.collapse_to(cursor, goal);
12702            });
12703        });
12704
12705        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12706        {
12707            cx.propagate();
12708        }
12709    }
12710
12711    pub fn move_up_by_lines(
12712        &mut self,
12713        action: &MoveUpByLines,
12714        window: &mut Window,
12715        cx: &mut Context<Self>,
12716    ) {
12717        if self.take_rename(true, window, cx).is_some() {
12718            return;
12719        }
12720
12721        if self.mode.is_single_line() {
12722            cx.propagate();
12723            return;
12724        }
12725
12726        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12727
12728        let text_layout_details = &self.text_layout_details(window);
12729
12730        self.change_selections(Default::default(), window, cx, |s| {
12731            s.move_with(|map, selection| {
12732                if !selection.is_empty() {
12733                    selection.goal = SelectionGoal::None;
12734                }
12735                let (cursor, goal) = movement::up_by_rows(
12736                    map,
12737                    selection.start,
12738                    action.lines,
12739                    selection.goal,
12740                    false,
12741                    text_layout_details,
12742                );
12743                selection.collapse_to(cursor, goal);
12744            });
12745        })
12746    }
12747
12748    pub fn move_down_by_lines(
12749        &mut self,
12750        action: &MoveDownByLines,
12751        window: &mut Window,
12752        cx: &mut Context<Self>,
12753    ) {
12754        if self.take_rename(true, window, cx).is_some() {
12755            return;
12756        }
12757
12758        if self.mode.is_single_line() {
12759            cx.propagate();
12760            return;
12761        }
12762
12763        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12764
12765        let text_layout_details = &self.text_layout_details(window);
12766
12767        self.change_selections(Default::default(), window, cx, |s| {
12768            s.move_with(|map, selection| {
12769                if !selection.is_empty() {
12770                    selection.goal = SelectionGoal::None;
12771                }
12772                let (cursor, goal) = movement::down_by_rows(
12773                    map,
12774                    selection.start,
12775                    action.lines,
12776                    selection.goal,
12777                    false,
12778                    text_layout_details,
12779                );
12780                selection.collapse_to(cursor, goal);
12781            });
12782        })
12783    }
12784
12785    pub fn select_down_by_lines(
12786        &mut self,
12787        action: &SelectDownByLines,
12788        window: &mut Window,
12789        cx: &mut Context<Self>,
12790    ) {
12791        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12792        let text_layout_details = &self.text_layout_details(window);
12793        self.change_selections(Default::default(), window, cx, |s| {
12794            s.move_heads_with(|map, head, goal| {
12795                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12796            })
12797        })
12798    }
12799
12800    pub fn select_up_by_lines(
12801        &mut self,
12802        action: &SelectUpByLines,
12803        window: &mut Window,
12804        cx: &mut Context<Self>,
12805    ) {
12806        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12807        let text_layout_details = &self.text_layout_details(window);
12808        self.change_selections(Default::default(), window, cx, |s| {
12809            s.move_heads_with(|map, head, goal| {
12810                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12811            })
12812        })
12813    }
12814
12815    pub fn select_page_up(
12816        &mut self,
12817        _: &SelectPageUp,
12818        window: &mut Window,
12819        cx: &mut Context<Self>,
12820    ) {
12821        let Some(row_count) = self.visible_row_count() else {
12822            return;
12823        };
12824
12825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12826
12827        let text_layout_details = &self.text_layout_details(window);
12828
12829        self.change_selections(Default::default(), window, cx, |s| {
12830            s.move_heads_with(|map, head, goal| {
12831                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12832            })
12833        })
12834    }
12835
12836    pub fn move_page_up(
12837        &mut self,
12838        action: &MovePageUp,
12839        window: &mut Window,
12840        cx: &mut Context<Self>,
12841    ) {
12842        if self.take_rename(true, window, cx).is_some() {
12843            return;
12844        }
12845
12846        if self
12847            .context_menu
12848            .borrow_mut()
12849            .as_mut()
12850            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12851            .unwrap_or(false)
12852        {
12853            return;
12854        }
12855
12856        if matches!(self.mode, EditorMode::SingleLine) {
12857            cx.propagate();
12858            return;
12859        }
12860
12861        let Some(row_count) = self.visible_row_count() else {
12862            return;
12863        };
12864
12865        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12866
12867        let effects = if action.center_cursor {
12868            SelectionEffects::scroll(Autoscroll::center())
12869        } else {
12870            SelectionEffects::default()
12871        };
12872
12873        let text_layout_details = &self.text_layout_details(window);
12874
12875        self.change_selections(effects, window, cx, |s| {
12876            s.move_with(|map, selection| {
12877                if !selection.is_empty() {
12878                    selection.goal = SelectionGoal::None;
12879                }
12880                let (cursor, goal) = movement::up_by_rows(
12881                    map,
12882                    selection.end,
12883                    row_count,
12884                    selection.goal,
12885                    false,
12886                    text_layout_details,
12887                );
12888                selection.collapse_to(cursor, goal);
12889            });
12890        });
12891    }
12892
12893    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12894        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12895        let text_layout_details = &self.text_layout_details(window);
12896        self.change_selections(Default::default(), window, cx, |s| {
12897            s.move_heads_with(|map, head, goal| {
12898                movement::up(map, head, goal, false, text_layout_details)
12899            })
12900        })
12901    }
12902
12903    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12904        self.take_rename(true, window, cx);
12905
12906        if self.mode.is_single_line() {
12907            cx.propagate();
12908            return;
12909        }
12910
12911        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12912
12913        let text_layout_details = &self.text_layout_details(window);
12914        let selection_count = self.selections.count();
12915        let first_selection = self.selections.first_anchor();
12916
12917        self.change_selections(Default::default(), window, cx, |s| {
12918            s.move_with(|map, selection| {
12919                if !selection.is_empty() {
12920                    selection.goal = SelectionGoal::None;
12921                }
12922                let (cursor, goal) = movement::down(
12923                    map,
12924                    selection.end,
12925                    selection.goal,
12926                    false,
12927                    text_layout_details,
12928                );
12929                selection.collapse_to(cursor, goal);
12930            });
12931        });
12932
12933        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12934        {
12935            cx.propagate();
12936        }
12937    }
12938
12939    pub fn select_page_down(
12940        &mut self,
12941        _: &SelectPageDown,
12942        window: &mut Window,
12943        cx: &mut Context<Self>,
12944    ) {
12945        let Some(row_count) = self.visible_row_count() else {
12946            return;
12947        };
12948
12949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12950
12951        let text_layout_details = &self.text_layout_details(window);
12952
12953        self.change_selections(Default::default(), window, cx, |s| {
12954            s.move_heads_with(|map, head, goal| {
12955                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12956            })
12957        })
12958    }
12959
12960    pub fn move_page_down(
12961        &mut self,
12962        action: &MovePageDown,
12963        window: &mut Window,
12964        cx: &mut Context<Self>,
12965    ) {
12966        if self.take_rename(true, window, cx).is_some() {
12967            return;
12968        }
12969
12970        if self
12971            .context_menu
12972            .borrow_mut()
12973            .as_mut()
12974            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12975            .unwrap_or(false)
12976        {
12977            return;
12978        }
12979
12980        if matches!(self.mode, EditorMode::SingleLine) {
12981            cx.propagate();
12982            return;
12983        }
12984
12985        let Some(row_count) = self.visible_row_count() else {
12986            return;
12987        };
12988
12989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12990
12991        let effects = if action.center_cursor {
12992            SelectionEffects::scroll(Autoscroll::center())
12993        } else {
12994            SelectionEffects::default()
12995        };
12996
12997        let text_layout_details = &self.text_layout_details(window);
12998        self.change_selections(effects, window, cx, |s| {
12999            s.move_with(|map, selection| {
13000                if !selection.is_empty() {
13001                    selection.goal = SelectionGoal::None;
13002                }
13003                let (cursor, goal) = movement::down_by_rows(
13004                    map,
13005                    selection.end,
13006                    row_count,
13007                    selection.goal,
13008                    false,
13009                    text_layout_details,
13010                );
13011                selection.collapse_to(cursor, goal);
13012            });
13013        });
13014    }
13015
13016    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13017        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13018        let text_layout_details = &self.text_layout_details(window);
13019        self.change_selections(Default::default(), window, cx, |s| {
13020            s.move_heads_with(|map, head, goal| {
13021                movement::down(map, head, goal, false, text_layout_details)
13022            })
13023        });
13024    }
13025
13026    pub fn context_menu_first(
13027        &mut self,
13028        _: &ContextMenuFirst,
13029        window: &mut Window,
13030        cx: &mut Context<Self>,
13031    ) {
13032        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13033            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13034        }
13035    }
13036
13037    pub fn context_menu_prev(
13038        &mut self,
13039        _: &ContextMenuPrevious,
13040        window: &mut Window,
13041        cx: &mut Context<Self>,
13042    ) {
13043        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13044            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13045        }
13046    }
13047
13048    pub fn context_menu_next(
13049        &mut self,
13050        _: &ContextMenuNext,
13051        window: &mut Window,
13052        cx: &mut Context<Self>,
13053    ) {
13054        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13055            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13056        }
13057    }
13058
13059    pub fn context_menu_last(
13060        &mut self,
13061        _: &ContextMenuLast,
13062        window: &mut Window,
13063        cx: &mut Context<Self>,
13064    ) {
13065        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13066            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13067        }
13068    }
13069
13070    pub fn signature_help_prev(
13071        &mut self,
13072        _: &SignatureHelpPrevious,
13073        _: &mut Window,
13074        cx: &mut Context<Self>,
13075    ) {
13076        if let Some(popover) = self.signature_help_state.popover_mut() {
13077            if popover.current_signature == 0 {
13078                popover.current_signature = popover.signatures.len() - 1;
13079            } else {
13080                popover.current_signature -= 1;
13081            }
13082            cx.notify();
13083        }
13084    }
13085
13086    pub fn signature_help_next(
13087        &mut self,
13088        _: &SignatureHelpNext,
13089        _: &mut Window,
13090        cx: &mut Context<Self>,
13091    ) {
13092        if let Some(popover) = self.signature_help_state.popover_mut() {
13093            if popover.current_signature + 1 == popover.signatures.len() {
13094                popover.current_signature = 0;
13095            } else {
13096                popover.current_signature += 1;
13097            }
13098            cx.notify();
13099        }
13100    }
13101
13102    pub fn move_to_previous_word_start(
13103        &mut self,
13104        _: &MoveToPreviousWordStart,
13105        window: &mut Window,
13106        cx: &mut Context<Self>,
13107    ) {
13108        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13109        self.change_selections(Default::default(), window, cx, |s| {
13110            s.move_cursors_with(|map, head, _| {
13111                (
13112                    movement::previous_word_start(map, head),
13113                    SelectionGoal::None,
13114                )
13115            });
13116        })
13117    }
13118
13119    pub fn move_to_previous_subword_start(
13120        &mut self,
13121        _: &MoveToPreviousSubwordStart,
13122        window: &mut Window,
13123        cx: &mut Context<Self>,
13124    ) {
13125        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13126        self.change_selections(Default::default(), window, cx, |s| {
13127            s.move_cursors_with(|map, head, _| {
13128                (
13129                    movement::previous_subword_start(map, head),
13130                    SelectionGoal::None,
13131                )
13132            });
13133        })
13134    }
13135
13136    pub fn select_to_previous_word_start(
13137        &mut self,
13138        _: &SelectToPreviousWordStart,
13139        window: &mut Window,
13140        cx: &mut Context<Self>,
13141    ) {
13142        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13143        self.change_selections(Default::default(), window, cx, |s| {
13144            s.move_heads_with(|map, head, _| {
13145                (
13146                    movement::previous_word_start(map, head),
13147                    SelectionGoal::None,
13148                )
13149            });
13150        })
13151    }
13152
13153    pub fn select_to_previous_subword_start(
13154        &mut self,
13155        _: &SelectToPreviousSubwordStart,
13156        window: &mut Window,
13157        cx: &mut Context<Self>,
13158    ) {
13159        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13160        self.change_selections(Default::default(), window, cx, |s| {
13161            s.move_heads_with(|map, head, _| {
13162                (
13163                    movement::previous_subword_start(map, head),
13164                    SelectionGoal::None,
13165                )
13166            });
13167        })
13168    }
13169
13170    pub fn delete_to_previous_word_start(
13171        &mut self,
13172        action: &DeleteToPreviousWordStart,
13173        window: &mut Window,
13174        cx: &mut Context<Self>,
13175    ) {
13176        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13177        self.transact(window, cx, |this, window, cx| {
13178            this.select_autoclose_pair(window, cx);
13179            this.change_selections(Default::default(), window, cx, |s| {
13180                s.move_with(|map, selection| {
13181                    if selection.is_empty() {
13182                        let mut cursor = if action.ignore_newlines {
13183                            movement::previous_word_start(map, selection.head())
13184                        } else {
13185                            movement::previous_word_start_or_newline(map, selection.head())
13186                        };
13187                        cursor = movement::adjust_greedy_deletion(
13188                            map,
13189                            selection.head(),
13190                            cursor,
13191                            action.ignore_brackets,
13192                        );
13193                        selection.set_head(cursor, SelectionGoal::None);
13194                    }
13195                });
13196            });
13197            this.insert("", window, cx);
13198        });
13199    }
13200
13201    pub fn delete_to_previous_subword_start(
13202        &mut self,
13203        _: &DeleteToPreviousSubwordStart,
13204        window: &mut Window,
13205        cx: &mut Context<Self>,
13206    ) {
13207        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13208        self.transact(window, cx, |this, window, cx| {
13209            this.select_autoclose_pair(window, cx);
13210            this.change_selections(Default::default(), window, cx, |s| {
13211                s.move_with(|map, selection| {
13212                    if selection.is_empty() {
13213                        let mut cursor = movement::previous_subword_start(map, selection.head());
13214                        cursor =
13215                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13216                        selection.set_head(cursor, SelectionGoal::None);
13217                    }
13218                });
13219            });
13220            this.insert("", window, cx);
13221        });
13222    }
13223
13224    pub fn move_to_next_word_end(
13225        &mut self,
13226        _: &MoveToNextWordEnd,
13227        window: &mut Window,
13228        cx: &mut Context<Self>,
13229    ) {
13230        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13231        self.change_selections(Default::default(), window, cx, |s| {
13232            s.move_cursors_with(|map, head, _| {
13233                (movement::next_word_end(map, head), SelectionGoal::None)
13234            });
13235        })
13236    }
13237
13238    pub fn move_to_next_subword_end(
13239        &mut self,
13240        _: &MoveToNextSubwordEnd,
13241        window: &mut Window,
13242        cx: &mut Context<Self>,
13243    ) {
13244        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13245        self.change_selections(Default::default(), window, cx, |s| {
13246            s.move_cursors_with(|map, head, _| {
13247                (movement::next_subword_end(map, head), SelectionGoal::None)
13248            });
13249        })
13250    }
13251
13252    pub fn select_to_next_word_end(
13253        &mut self,
13254        _: &SelectToNextWordEnd,
13255        window: &mut Window,
13256        cx: &mut Context<Self>,
13257    ) {
13258        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13259        self.change_selections(Default::default(), window, cx, |s| {
13260            s.move_heads_with(|map, head, _| {
13261                (movement::next_word_end(map, head), SelectionGoal::None)
13262            });
13263        })
13264    }
13265
13266    pub fn select_to_next_subword_end(
13267        &mut self,
13268        _: &SelectToNextSubwordEnd,
13269        window: &mut Window,
13270        cx: &mut Context<Self>,
13271    ) {
13272        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13273        self.change_selections(Default::default(), window, cx, |s| {
13274            s.move_heads_with(|map, head, _| {
13275                (movement::next_subword_end(map, head), SelectionGoal::None)
13276            });
13277        })
13278    }
13279
13280    pub fn delete_to_next_word_end(
13281        &mut self,
13282        action: &DeleteToNextWordEnd,
13283        window: &mut Window,
13284        cx: &mut Context<Self>,
13285    ) {
13286        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13287        self.transact(window, cx, |this, window, cx| {
13288            this.change_selections(Default::default(), window, cx, |s| {
13289                s.move_with(|map, selection| {
13290                    if selection.is_empty() {
13291                        let mut cursor = if action.ignore_newlines {
13292                            movement::next_word_end(map, selection.head())
13293                        } else {
13294                            movement::next_word_end_or_newline(map, selection.head())
13295                        };
13296                        cursor = movement::adjust_greedy_deletion(
13297                            map,
13298                            selection.head(),
13299                            cursor,
13300                            action.ignore_brackets,
13301                        );
13302                        selection.set_head(cursor, SelectionGoal::None);
13303                    }
13304                });
13305            });
13306            this.insert("", window, cx);
13307        });
13308    }
13309
13310    pub fn delete_to_next_subword_end(
13311        &mut self,
13312        _: &DeleteToNextSubwordEnd,
13313        window: &mut Window,
13314        cx: &mut Context<Self>,
13315    ) {
13316        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13317        self.transact(window, cx, |this, window, cx| {
13318            this.change_selections(Default::default(), window, cx, |s| {
13319                s.move_with(|map, selection| {
13320                    if selection.is_empty() {
13321                        let mut cursor = movement::next_subword_end(map, selection.head());
13322                        cursor =
13323                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13324                        selection.set_head(cursor, SelectionGoal::None);
13325                    }
13326                });
13327            });
13328            this.insert("", window, cx);
13329        });
13330    }
13331
13332    pub fn move_to_beginning_of_line(
13333        &mut self,
13334        action: &MoveToBeginningOfLine,
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                (
13342                    movement::indented_line_beginning(
13343                        map,
13344                        head,
13345                        action.stop_at_soft_wraps,
13346                        action.stop_at_indent,
13347                    ),
13348                    SelectionGoal::None,
13349                )
13350            });
13351        })
13352    }
13353
13354    pub fn select_to_beginning_of_line(
13355        &mut self,
13356        action: &SelectToBeginningOfLine,
13357        window: &mut Window,
13358        cx: &mut Context<Self>,
13359    ) {
13360        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13361        self.change_selections(Default::default(), window, cx, |s| {
13362            s.move_heads_with(|map, head, _| {
13363                (
13364                    movement::indented_line_beginning(
13365                        map,
13366                        head,
13367                        action.stop_at_soft_wraps,
13368                        action.stop_at_indent,
13369                    ),
13370                    SelectionGoal::None,
13371                )
13372            });
13373        });
13374    }
13375
13376    pub fn delete_to_beginning_of_line(
13377        &mut self,
13378        action: &DeleteToBeginningOfLine,
13379        window: &mut Window,
13380        cx: &mut Context<Self>,
13381    ) {
13382        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13383        self.transact(window, cx, |this, window, cx| {
13384            this.change_selections(Default::default(), window, cx, |s| {
13385                s.move_with(|_, selection| {
13386                    selection.reversed = true;
13387                });
13388            });
13389
13390            this.select_to_beginning_of_line(
13391                &SelectToBeginningOfLine {
13392                    stop_at_soft_wraps: false,
13393                    stop_at_indent: action.stop_at_indent,
13394                },
13395                window,
13396                cx,
13397            );
13398            this.backspace(&Backspace, window, cx);
13399        });
13400    }
13401
13402    pub fn move_to_end_of_line(
13403        &mut self,
13404        action: &MoveToEndOfLine,
13405        window: &mut Window,
13406        cx: &mut Context<Self>,
13407    ) {
13408        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13409        self.change_selections(Default::default(), window, cx, |s| {
13410            s.move_cursors_with(|map, head, _| {
13411                (
13412                    movement::line_end(map, head, action.stop_at_soft_wraps),
13413                    SelectionGoal::None,
13414                )
13415            });
13416        })
13417    }
13418
13419    pub fn select_to_end_of_line(
13420        &mut self,
13421        action: &SelectToEndOfLine,
13422        window: &mut Window,
13423        cx: &mut Context<Self>,
13424    ) {
13425        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13426        self.change_selections(Default::default(), window, cx, |s| {
13427            s.move_heads_with(|map, head, _| {
13428                (
13429                    movement::line_end(map, head, action.stop_at_soft_wraps),
13430                    SelectionGoal::None,
13431                )
13432            });
13433        })
13434    }
13435
13436    pub fn delete_to_end_of_line(
13437        &mut self,
13438        _: &DeleteToEndOfLine,
13439        window: &mut Window,
13440        cx: &mut Context<Self>,
13441    ) {
13442        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13443        self.transact(window, cx, |this, window, cx| {
13444            this.select_to_end_of_line(
13445                &SelectToEndOfLine {
13446                    stop_at_soft_wraps: false,
13447                },
13448                window,
13449                cx,
13450            );
13451            this.delete(&Delete, window, cx);
13452        });
13453    }
13454
13455    pub fn cut_to_end_of_line(
13456        &mut self,
13457        _: &CutToEndOfLine,
13458        window: &mut Window,
13459        cx: &mut Context<Self>,
13460    ) {
13461        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13462        self.transact(window, cx, |this, window, cx| {
13463            this.select_to_end_of_line(
13464                &SelectToEndOfLine {
13465                    stop_at_soft_wraps: false,
13466                },
13467                window,
13468                cx,
13469            );
13470            this.cut(&Cut, window, cx);
13471        });
13472    }
13473
13474    pub fn move_to_start_of_paragraph(
13475        &mut self,
13476        _: &MoveToStartOfParagraph,
13477        window: &mut Window,
13478        cx: &mut Context<Self>,
13479    ) {
13480        if matches!(self.mode, EditorMode::SingleLine) {
13481            cx.propagate();
13482            return;
13483        }
13484        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13485        self.change_selections(Default::default(), window, cx, |s| {
13486            s.move_with(|map, selection| {
13487                selection.collapse_to(
13488                    movement::start_of_paragraph(map, selection.head(), 1),
13489                    SelectionGoal::None,
13490                )
13491            });
13492        })
13493    }
13494
13495    pub fn move_to_end_of_paragraph(
13496        &mut self,
13497        _: &MoveToEndOfParagraph,
13498        window: &mut Window,
13499        cx: &mut Context<Self>,
13500    ) {
13501        if matches!(self.mode, EditorMode::SingleLine) {
13502            cx.propagate();
13503            return;
13504        }
13505        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13506        self.change_selections(Default::default(), window, cx, |s| {
13507            s.move_with(|map, selection| {
13508                selection.collapse_to(
13509                    movement::end_of_paragraph(map, selection.head(), 1),
13510                    SelectionGoal::None,
13511                )
13512            });
13513        })
13514    }
13515
13516    pub fn select_to_start_of_paragraph(
13517        &mut self,
13518        _: &SelectToStartOfParagraph,
13519        window: &mut Window,
13520        cx: &mut Context<Self>,
13521    ) {
13522        if matches!(self.mode, EditorMode::SingleLine) {
13523            cx.propagate();
13524            return;
13525        }
13526        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13527        self.change_selections(Default::default(), window, cx, |s| {
13528            s.move_heads_with(|map, head, _| {
13529                (
13530                    movement::start_of_paragraph(map, head, 1),
13531                    SelectionGoal::None,
13532                )
13533            });
13534        })
13535    }
13536
13537    pub fn select_to_end_of_paragraph(
13538        &mut self,
13539        _: &SelectToEndOfParagraph,
13540        window: &mut Window,
13541        cx: &mut Context<Self>,
13542    ) {
13543        if matches!(self.mode, EditorMode::SingleLine) {
13544            cx.propagate();
13545            return;
13546        }
13547        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13548        self.change_selections(Default::default(), window, cx, |s| {
13549            s.move_heads_with(|map, head, _| {
13550                (
13551                    movement::end_of_paragraph(map, head, 1),
13552                    SelectionGoal::None,
13553                )
13554            });
13555        })
13556    }
13557
13558    pub fn move_to_start_of_excerpt(
13559        &mut self,
13560        _: &MoveToStartOfExcerpt,
13561        window: &mut Window,
13562        cx: &mut Context<Self>,
13563    ) {
13564        if matches!(self.mode, EditorMode::SingleLine) {
13565            cx.propagate();
13566            return;
13567        }
13568        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13569        self.change_selections(Default::default(), window, cx, |s| {
13570            s.move_with(|map, selection| {
13571                selection.collapse_to(
13572                    movement::start_of_excerpt(
13573                        map,
13574                        selection.head(),
13575                        workspace::searchable::Direction::Prev,
13576                    ),
13577                    SelectionGoal::None,
13578                )
13579            });
13580        })
13581    }
13582
13583    pub fn move_to_start_of_next_excerpt(
13584        &mut self,
13585        _: &MoveToStartOfNextExcerpt,
13586        window: &mut Window,
13587        cx: &mut Context<Self>,
13588    ) {
13589        if matches!(self.mode, EditorMode::SingleLine) {
13590            cx.propagate();
13591            return;
13592        }
13593
13594        self.change_selections(Default::default(), window, cx, |s| {
13595            s.move_with(|map, selection| {
13596                selection.collapse_to(
13597                    movement::start_of_excerpt(
13598                        map,
13599                        selection.head(),
13600                        workspace::searchable::Direction::Next,
13601                    ),
13602                    SelectionGoal::None,
13603                )
13604            });
13605        })
13606    }
13607
13608    pub fn move_to_end_of_excerpt(
13609        &mut self,
13610        _: &MoveToEndOfExcerpt,
13611        window: &mut Window,
13612        cx: &mut Context<Self>,
13613    ) {
13614        if matches!(self.mode, EditorMode::SingleLine) {
13615            cx.propagate();
13616            return;
13617        }
13618        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13619        self.change_selections(Default::default(), window, cx, |s| {
13620            s.move_with(|map, selection| {
13621                selection.collapse_to(
13622                    movement::end_of_excerpt(
13623                        map,
13624                        selection.head(),
13625                        workspace::searchable::Direction::Next,
13626                    ),
13627                    SelectionGoal::None,
13628                )
13629            });
13630        })
13631    }
13632
13633    pub fn move_to_end_of_previous_excerpt(
13634        &mut self,
13635        _: &MoveToEndOfPreviousExcerpt,
13636        window: &mut Window,
13637        cx: &mut Context<Self>,
13638    ) {
13639        if matches!(self.mode, EditorMode::SingleLine) {
13640            cx.propagate();
13641            return;
13642        }
13643        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13644        self.change_selections(Default::default(), window, cx, |s| {
13645            s.move_with(|map, selection| {
13646                selection.collapse_to(
13647                    movement::end_of_excerpt(
13648                        map,
13649                        selection.head(),
13650                        workspace::searchable::Direction::Prev,
13651                    ),
13652                    SelectionGoal::None,
13653                )
13654            });
13655        })
13656    }
13657
13658    pub fn select_to_start_of_excerpt(
13659        &mut self,
13660        _: &SelectToStartOfExcerpt,
13661        window: &mut Window,
13662        cx: &mut Context<Self>,
13663    ) {
13664        if matches!(self.mode, EditorMode::SingleLine) {
13665            cx.propagate();
13666            return;
13667        }
13668        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13669        self.change_selections(Default::default(), window, cx, |s| {
13670            s.move_heads_with(|map, head, _| {
13671                (
13672                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13673                    SelectionGoal::None,
13674                )
13675            });
13676        })
13677    }
13678
13679    pub fn select_to_start_of_next_excerpt(
13680        &mut self,
13681        _: &SelectToStartOfNextExcerpt,
13682        window: &mut Window,
13683        cx: &mut Context<Self>,
13684    ) {
13685        if matches!(self.mode, EditorMode::SingleLine) {
13686            cx.propagate();
13687            return;
13688        }
13689        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13690        self.change_selections(Default::default(), window, cx, |s| {
13691            s.move_heads_with(|map, head, _| {
13692                (
13693                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13694                    SelectionGoal::None,
13695                )
13696            });
13697        })
13698    }
13699
13700    pub fn select_to_end_of_excerpt(
13701        &mut self,
13702        _: &SelectToEndOfExcerpt,
13703        window: &mut Window,
13704        cx: &mut Context<Self>,
13705    ) {
13706        if matches!(self.mode, EditorMode::SingleLine) {
13707            cx.propagate();
13708            return;
13709        }
13710        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13711        self.change_selections(Default::default(), window, cx, |s| {
13712            s.move_heads_with(|map, head, _| {
13713                (
13714                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13715                    SelectionGoal::None,
13716                )
13717            });
13718        })
13719    }
13720
13721    pub fn select_to_end_of_previous_excerpt(
13722        &mut self,
13723        _: &SelectToEndOfPreviousExcerpt,
13724        window: &mut Window,
13725        cx: &mut Context<Self>,
13726    ) {
13727        if matches!(self.mode, EditorMode::SingleLine) {
13728            cx.propagate();
13729            return;
13730        }
13731        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13732        self.change_selections(Default::default(), window, cx, |s| {
13733            s.move_heads_with(|map, head, _| {
13734                (
13735                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13736                    SelectionGoal::None,
13737                )
13738            });
13739        })
13740    }
13741
13742    pub fn move_to_beginning(
13743        &mut self,
13744        _: &MoveToBeginning,
13745        window: &mut Window,
13746        cx: &mut Context<Self>,
13747    ) {
13748        if matches!(self.mode, EditorMode::SingleLine) {
13749            cx.propagate();
13750            return;
13751        }
13752        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13753        self.change_selections(Default::default(), window, cx, |s| {
13754            s.select_ranges(vec![0..0]);
13755        });
13756    }
13757
13758    pub fn select_to_beginning(
13759        &mut self,
13760        _: &SelectToBeginning,
13761        window: &mut Window,
13762        cx: &mut Context<Self>,
13763    ) {
13764        let mut selection = self.selections.last::<Point>(cx);
13765        selection.set_head(Point::zero(), SelectionGoal::None);
13766        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13767        self.change_selections(Default::default(), window, cx, |s| {
13768            s.select(vec![selection]);
13769        });
13770    }
13771
13772    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13773        if matches!(self.mode, EditorMode::SingleLine) {
13774            cx.propagate();
13775            return;
13776        }
13777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13778        let cursor = self.buffer.read(cx).read(cx).len();
13779        self.change_selections(Default::default(), window, cx, |s| {
13780            s.select_ranges(vec![cursor..cursor])
13781        });
13782    }
13783
13784    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13785        self.nav_history = nav_history;
13786    }
13787
13788    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13789        self.nav_history.as_ref()
13790    }
13791
13792    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13793        self.push_to_nav_history(
13794            self.selections.newest_anchor().head(),
13795            None,
13796            false,
13797            true,
13798            cx,
13799        );
13800    }
13801
13802    fn push_to_nav_history(
13803        &mut self,
13804        cursor_anchor: Anchor,
13805        new_position: Option<Point>,
13806        is_deactivate: bool,
13807        always: bool,
13808        cx: &mut Context<Self>,
13809    ) {
13810        if let Some(nav_history) = self.nav_history.as_mut() {
13811            let buffer = self.buffer.read(cx).read(cx);
13812            let cursor_position = cursor_anchor.to_point(&buffer);
13813            let scroll_state = self.scroll_manager.anchor();
13814            let scroll_top_row = scroll_state.top_row(&buffer);
13815            drop(buffer);
13816
13817            if let Some(new_position) = new_position {
13818                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13819                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13820                    return;
13821                }
13822            }
13823
13824            nav_history.push(
13825                Some(NavigationData {
13826                    cursor_anchor,
13827                    cursor_position,
13828                    scroll_anchor: scroll_state,
13829                    scroll_top_row,
13830                }),
13831                cx,
13832            );
13833            cx.emit(EditorEvent::PushedToNavHistory {
13834                anchor: cursor_anchor,
13835                is_deactivate,
13836            })
13837        }
13838    }
13839
13840    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13841        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13842        let buffer = self.buffer.read(cx).snapshot(cx);
13843        let mut selection = self.selections.first::<usize>(cx);
13844        selection.set_head(buffer.len(), SelectionGoal::None);
13845        self.change_selections(Default::default(), window, cx, |s| {
13846            s.select(vec![selection]);
13847        });
13848    }
13849
13850    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13851        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13852        let end = self.buffer.read(cx).read(cx).len();
13853        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13854            s.select_ranges(vec![0..end]);
13855        });
13856    }
13857
13858    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13859        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13860        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13861        let mut selections = self.selections.all::<Point>(cx);
13862        let max_point = display_map.buffer_snapshot.max_point();
13863        for selection in &mut selections {
13864            let rows = selection.spanned_rows(true, &display_map);
13865            selection.start = Point::new(rows.start.0, 0);
13866            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13867            selection.reversed = false;
13868        }
13869        self.change_selections(Default::default(), window, cx, |s| {
13870            s.select(selections);
13871        });
13872    }
13873
13874    pub fn split_selection_into_lines(
13875        &mut self,
13876        action: &SplitSelectionIntoLines,
13877        window: &mut Window,
13878        cx: &mut Context<Self>,
13879    ) {
13880        let selections = self
13881            .selections
13882            .all::<Point>(cx)
13883            .into_iter()
13884            .map(|selection| selection.start..selection.end)
13885            .collect::<Vec<_>>();
13886        self.unfold_ranges(&selections, true, true, cx);
13887
13888        let mut new_selection_ranges = Vec::new();
13889        {
13890            let buffer = self.buffer.read(cx).read(cx);
13891            for selection in selections {
13892                for row in selection.start.row..selection.end.row {
13893                    let line_start = Point::new(row, 0);
13894                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13895
13896                    if action.keep_selections {
13897                        // Keep the selection range for each line
13898                        let selection_start = if row == selection.start.row {
13899                            selection.start
13900                        } else {
13901                            line_start
13902                        };
13903                        new_selection_ranges.push(selection_start..line_end);
13904                    } else {
13905                        // Collapse to cursor at end of line
13906                        new_selection_ranges.push(line_end..line_end);
13907                    }
13908                }
13909
13910                let is_multiline_selection = selection.start.row != selection.end.row;
13911                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13912                // so this action feels more ergonomic when paired with other selection operations
13913                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13914                if !should_skip_last {
13915                    if action.keep_selections {
13916                        if is_multiline_selection {
13917                            let line_start = Point::new(selection.end.row, 0);
13918                            new_selection_ranges.push(line_start..selection.end);
13919                        } else {
13920                            new_selection_ranges.push(selection.start..selection.end);
13921                        }
13922                    } else {
13923                        new_selection_ranges.push(selection.end..selection.end);
13924                    }
13925                }
13926            }
13927        }
13928        self.change_selections(Default::default(), window, cx, |s| {
13929            s.select_ranges(new_selection_ranges);
13930        });
13931    }
13932
13933    pub fn add_selection_above(
13934        &mut self,
13935        _: &AddSelectionAbove,
13936        window: &mut Window,
13937        cx: &mut Context<Self>,
13938    ) {
13939        self.add_selection(true, window, cx);
13940    }
13941
13942    pub fn add_selection_below(
13943        &mut self,
13944        _: &AddSelectionBelow,
13945        window: &mut Window,
13946        cx: &mut Context<Self>,
13947    ) {
13948        self.add_selection(false, window, cx);
13949    }
13950
13951    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13952        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13953
13954        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13955        let all_selections = self.selections.all::<Point>(cx);
13956        let text_layout_details = self.text_layout_details(window);
13957
13958        let (mut columnar_selections, new_selections_to_columnarize) = {
13959            if let Some(state) = self.add_selections_state.as_ref() {
13960                let columnar_selection_ids: HashSet<_> = state
13961                    .groups
13962                    .iter()
13963                    .flat_map(|group| group.stack.iter())
13964                    .copied()
13965                    .collect();
13966
13967                all_selections
13968                    .into_iter()
13969                    .partition(|s| columnar_selection_ids.contains(&s.id))
13970            } else {
13971                (Vec::new(), all_selections)
13972            }
13973        };
13974
13975        let mut state = self
13976            .add_selections_state
13977            .take()
13978            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13979
13980        for selection in new_selections_to_columnarize {
13981            let range = selection.display_range(&display_map).sorted();
13982            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13983            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13984            let positions = start_x.min(end_x)..start_x.max(end_x);
13985            let mut stack = Vec::new();
13986            for row in range.start.row().0..=range.end.row().0 {
13987                if let Some(selection) = self.selections.build_columnar_selection(
13988                    &display_map,
13989                    DisplayRow(row),
13990                    &positions,
13991                    selection.reversed,
13992                    &text_layout_details,
13993                ) {
13994                    stack.push(selection.id);
13995                    columnar_selections.push(selection);
13996                }
13997            }
13998            if !stack.is_empty() {
13999                if above {
14000                    stack.reverse();
14001                }
14002                state.groups.push(AddSelectionsGroup { above, stack });
14003            }
14004        }
14005
14006        let mut final_selections = Vec::new();
14007        let end_row = if above {
14008            DisplayRow(0)
14009        } else {
14010            display_map.max_point().row()
14011        };
14012
14013        let mut last_added_item_per_group = HashMap::default();
14014        for group in state.groups.iter_mut() {
14015            if let Some(last_id) = group.stack.last() {
14016                last_added_item_per_group.insert(*last_id, group);
14017            }
14018        }
14019
14020        for selection in columnar_selections {
14021            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14022                if above == group.above {
14023                    let range = selection.display_range(&display_map).sorted();
14024                    debug_assert_eq!(range.start.row(), range.end.row());
14025                    let mut row = range.start.row();
14026                    let positions =
14027                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14028                            px(start)..px(end)
14029                        } else {
14030                            let start_x =
14031                                display_map.x_for_display_point(range.start, &text_layout_details);
14032                            let end_x =
14033                                display_map.x_for_display_point(range.end, &text_layout_details);
14034                            start_x.min(end_x)..start_x.max(end_x)
14035                        };
14036
14037                    let mut maybe_new_selection = None;
14038                    while row != end_row {
14039                        if above {
14040                            row.0 -= 1;
14041                        } else {
14042                            row.0 += 1;
14043                        }
14044                        if let Some(new_selection) = self.selections.build_columnar_selection(
14045                            &display_map,
14046                            row,
14047                            &positions,
14048                            selection.reversed,
14049                            &text_layout_details,
14050                        ) {
14051                            maybe_new_selection = Some(new_selection);
14052                            break;
14053                        }
14054                    }
14055
14056                    if let Some(new_selection) = maybe_new_selection {
14057                        group.stack.push(new_selection.id);
14058                        if above {
14059                            final_selections.push(new_selection);
14060                            final_selections.push(selection);
14061                        } else {
14062                            final_selections.push(selection);
14063                            final_selections.push(new_selection);
14064                        }
14065                    } else {
14066                        final_selections.push(selection);
14067                    }
14068                } else {
14069                    group.stack.pop();
14070                }
14071            } else {
14072                final_selections.push(selection);
14073            }
14074        }
14075
14076        self.change_selections(Default::default(), window, cx, |s| {
14077            s.select(final_selections);
14078        });
14079
14080        let final_selection_ids: HashSet<_> = self
14081            .selections
14082            .all::<Point>(cx)
14083            .iter()
14084            .map(|s| s.id)
14085            .collect();
14086        state.groups.retain_mut(|group| {
14087            // selections might get merged above so we remove invalid items from stacks
14088            group.stack.retain(|id| final_selection_ids.contains(id));
14089
14090            // single selection in stack can be treated as initial state
14091            group.stack.len() > 1
14092        });
14093
14094        if !state.groups.is_empty() {
14095            self.add_selections_state = Some(state);
14096        }
14097    }
14098
14099    fn select_match_ranges(
14100        &mut self,
14101        range: Range<usize>,
14102        reversed: bool,
14103        replace_newest: bool,
14104        auto_scroll: Option<Autoscroll>,
14105        window: &mut Window,
14106        cx: &mut Context<Editor>,
14107    ) {
14108        self.unfold_ranges(
14109            std::slice::from_ref(&range),
14110            false,
14111            auto_scroll.is_some(),
14112            cx,
14113        );
14114        let effects = if let Some(scroll) = auto_scroll {
14115            SelectionEffects::scroll(scroll)
14116        } else {
14117            SelectionEffects::no_scroll()
14118        };
14119        self.change_selections(effects, window, cx, |s| {
14120            if replace_newest {
14121                s.delete(s.newest_anchor().id);
14122            }
14123            if reversed {
14124                s.insert_range(range.end..range.start);
14125            } else {
14126                s.insert_range(range);
14127            }
14128        });
14129    }
14130
14131    pub fn select_next_match_internal(
14132        &mut self,
14133        display_map: &DisplaySnapshot,
14134        replace_newest: bool,
14135        autoscroll: Option<Autoscroll>,
14136        window: &mut Window,
14137        cx: &mut Context<Self>,
14138    ) -> Result<()> {
14139        let buffer = &display_map.buffer_snapshot;
14140        let mut selections = self.selections.all::<usize>(cx);
14141        if let Some(mut select_next_state) = self.select_next_state.take() {
14142            let query = &select_next_state.query;
14143            if !select_next_state.done {
14144                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14145                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14146                let mut next_selected_range = None;
14147
14148                let bytes_after_last_selection =
14149                    buffer.bytes_in_range(last_selection.end..buffer.len());
14150                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14151                let query_matches = query
14152                    .stream_find_iter(bytes_after_last_selection)
14153                    .map(|result| (last_selection.end, result))
14154                    .chain(
14155                        query
14156                            .stream_find_iter(bytes_before_first_selection)
14157                            .map(|result| (0, result)),
14158                    );
14159
14160                for (start_offset, query_match) in query_matches {
14161                    let query_match = query_match.unwrap(); // can only fail due to I/O
14162                    let offset_range =
14163                        start_offset + query_match.start()..start_offset + query_match.end();
14164
14165                    if !select_next_state.wordwise
14166                        || (!buffer.is_inside_word(offset_range.start, false)
14167                            && !buffer.is_inside_word(offset_range.end, false))
14168                    {
14169                        // TODO: This is n^2, because we might check all the selections
14170                        if !selections
14171                            .iter()
14172                            .any(|selection| selection.range().overlaps(&offset_range))
14173                        {
14174                            next_selected_range = Some(offset_range);
14175                            break;
14176                        }
14177                    }
14178                }
14179
14180                if let Some(next_selected_range) = next_selected_range {
14181                    self.select_match_ranges(
14182                        next_selected_range,
14183                        last_selection.reversed,
14184                        replace_newest,
14185                        autoscroll,
14186                        window,
14187                        cx,
14188                    );
14189                } else {
14190                    select_next_state.done = true;
14191                }
14192            }
14193
14194            self.select_next_state = Some(select_next_state);
14195        } else {
14196            let mut only_carets = true;
14197            let mut same_text_selected = true;
14198            let mut selected_text = None;
14199
14200            let mut selections_iter = selections.iter().peekable();
14201            while let Some(selection) = selections_iter.next() {
14202                if selection.start != selection.end {
14203                    only_carets = false;
14204                }
14205
14206                if same_text_selected {
14207                    if selected_text.is_none() {
14208                        selected_text =
14209                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14210                    }
14211
14212                    if let Some(next_selection) = selections_iter.peek() {
14213                        if next_selection.range().len() == selection.range().len() {
14214                            let next_selected_text = buffer
14215                                .text_for_range(next_selection.range())
14216                                .collect::<String>();
14217                            if Some(next_selected_text) != selected_text {
14218                                same_text_selected = false;
14219                                selected_text = None;
14220                            }
14221                        } else {
14222                            same_text_selected = false;
14223                            selected_text = None;
14224                        }
14225                    }
14226                }
14227            }
14228
14229            if only_carets {
14230                for selection in &mut selections {
14231                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14232                    selection.start = word_range.start;
14233                    selection.end = word_range.end;
14234                    selection.goal = SelectionGoal::None;
14235                    selection.reversed = false;
14236                    self.select_match_ranges(
14237                        selection.start..selection.end,
14238                        selection.reversed,
14239                        replace_newest,
14240                        autoscroll,
14241                        window,
14242                        cx,
14243                    );
14244                }
14245
14246                if selections.len() == 1 {
14247                    let selection = selections
14248                        .last()
14249                        .expect("ensured that there's only one selection");
14250                    let query = buffer
14251                        .text_for_range(selection.start..selection.end)
14252                        .collect::<String>();
14253                    let is_empty = query.is_empty();
14254                    let select_state = SelectNextState {
14255                        query: AhoCorasick::new(&[query])?,
14256                        wordwise: true,
14257                        done: is_empty,
14258                    };
14259                    self.select_next_state = Some(select_state);
14260                } else {
14261                    self.select_next_state = None;
14262                }
14263            } else if let Some(selected_text) = selected_text {
14264                self.select_next_state = Some(SelectNextState {
14265                    query: AhoCorasick::new(&[selected_text])?,
14266                    wordwise: false,
14267                    done: false,
14268                });
14269                self.select_next_match_internal(
14270                    display_map,
14271                    replace_newest,
14272                    autoscroll,
14273                    window,
14274                    cx,
14275                )?;
14276            }
14277        }
14278        Ok(())
14279    }
14280
14281    pub fn select_all_matches(
14282        &mut self,
14283        _action: &SelectAllMatches,
14284        window: &mut Window,
14285        cx: &mut Context<Self>,
14286    ) -> Result<()> {
14287        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14288
14289        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14290
14291        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14292        let Some(select_next_state) = self.select_next_state.as_mut() else {
14293            return Ok(());
14294        };
14295        if select_next_state.done {
14296            return Ok(());
14297        }
14298
14299        let mut new_selections = Vec::new();
14300
14301        let reversed = self.selections.oldest::<usize>(cx).reversed;
14302        let buffer = &display_map.buffer_snapshot;
14303        let query_matches = select_next_state
14304            .query
14305            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14306
14307        for query_match in query_matches.into_iter() {
14308            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14309            let offset_range = if reversed {
14310                query_match.end()..query_match.start()
14311            } else {
14312                query_match.start()..query_match.end()
14313            };
14314
14315            if !select_next_state.wordwise
14316                || (!buffer.is_inside_word(offset_range.start, false)
14317                    && !buffer.is_inside_word(offset_range.end, false))
14318            {
14319                new_selections.push(offset_range.start..offset_range.end);
14320            }
14321        }
14322
14323        select_next_state.done = true;
14324
14325        if new_selections.is_empty() {
14326            log::error!("bug: new_selections is empty in select_all_matches");
14327            return Ok(());
14328        }
14329
14330        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14331        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14332            selections.select_ranges(new_selections)
14333        });
14334
14335        Ok(())
14336    }
14337
14338    pub fn select_next(
14339        &mut self,
14340        action: &SelectNext,
14341        window: &mut Window,
14342        cx: &mut Context<Self>,
14343    ) -> Result<()> {
14344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14345        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14346        self.select_next_match_internal(
14347            &display_map,
14348            action.replace_newest,
14349            Some(Autoscroll::newest()),
14350            window,
14351            cx,
14352        )?;
14353        Ok(())
14354    }
14355
14356    pub fn select_previous(
14357        &mut self,
14358        action: &SelectPrevious,
14359        window: &mut Window,
14360        cx: &mut Context<Self>,
14361    ) -> Result<()> {
14362        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14363        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14364        let buffer = &display_map.buffer_snapshot;
14365        let mut selections = self.selections.all::<usize>(cx);
14366        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14367            let query = &select_prev_state.query;
14368            if !select_prev_state.done {
14369                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14370                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14371                let mut next_selected_range = None;
14372                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14373                let bytes_before_last_selection =
14374                    buffer.reversed_bytes_in_range(0..last_selection.start);
14375                let bytes_after_first_selection =
14376                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14377                let query_matches = query
14378                    .stream_find_iter(bytes_before_last_selection)
14379                    .map(|result| (last_selection.start, result))
14380                    .chain(
14381                        query
14382                            .stream_find_iter(bytes_after_first_selection)
14383                            .map(|result| (buffer.len(), result)),
14384                    );
14385                for (end_offset, query_match) in query_matches {
14386                    let query_match = query_match.unwrap(); // can only fail due to I/O
14387                    let offset_range =
14388                        end_offset - query_match.end()..end_offset - query_match.start();
14389
14390                    if !select_prev_state.wordwise
14391                        || (!buffer.is_inside_word(offset_range.start, false)
14392                            && !buffer.is_inside_word(offset_range.end, false))
14393                    {
14394                        next_selected_range = Some(offset_range);
14395                        break;
14396                    }
14397                }
14398
14399                if let Some(next_selected_range) = next_selected_range {
14400                    self.select_match_ranges(
14401                        next_selected_range,
14402                        last_selection.reversed,
14403                        action.replace_newest,
14404                        Some(Autoscroll::newest()),
14405                        window,
14406                        cx,
14407                    );
14408                } else {
14409                    select_prev_state.done = true;
14410                }
14411            }
14412
14413            self.select_prev_state = Some(select_prev_state);
14414        } else {
14415            let mut only_carets = true;
14416            let mut same_text_selected = true;
14417            let mut selected_text = None;
14418
14419            let mut selections_iter = selections.iter().peekable();
14420            while let Some(selection) = selections_iter.next() {
14421                if selection.start != selection.end {
14422                    only_carets = false;
14423                }
14424
14425                if same_text_selected {
14426                    if selected_text.is_none() {
14427                        selected_text =
14428                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14429                    }
14430
14431                    if let Some(next_selection) = selections_iter.peek() {
14432                        if next_selection.range().len() == selection.range().len() {
14433                            let next_selected_text = buffer
14434                                .text_for_range(next_selection.range())
14435                                .collect::<String>();
14436                            if Some(next_selected_text) != selected_text {
14437                                same_text_selected = false;
14438                                selected_text = None;
14439                            }
14440                        } else {
14441                            same_text_selected = false;
14442                            selected_text = None;
14443                        }
14444                    }
14445                }
14446            }
14447
14448            if only_carets {
14449                for selection in &mut selections {
14450                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14451                    selection.start = word_range.start;
14452                    selection.end = word_range.end;
14453                    selection.goal = SelectionGoal::None;
14454                    selection.reversed = false;
14455                    self.select_match_ranges(
14456                        selection.start..selection.end,
14457                        selection.reversed,
14458                        action.replace_newest,
14459                        Some(Autoscroll::newest()),
14460                        window,
14461                        cx,
14462                    );
14463                }
14464                if selections.len() == 1 {
14465                    let selection = selections
14466                        .last()
14467                        .expect("ensured that there's only one selection");
14468                    let query = buffer
14469                        .text_for_range(selection.start..selection.end)
14470                        .collect::<String>();
14471                    let is_empty = query.is_empty();
14472                    let select_state = SelectNextState {
14473                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14474                        wordwise: true,
14475                        done: is_empty,
14476                    };
14477                    self.select_prev_state = Some(select_state);
14478                } else {
14479                    self.select_prev_state = None;
14480                }
14481            } else if let Some(selected_text) = selected_text {
14482                self.select_prev_state = Some(SelectNextState {
14483                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14484                    wordwise: false,
14485                    done: false,
14486                });
14487                self.select_previous(action, window, cx)?;
14488            }
14489        }
14490        Ok(())
14491    }
14492
14493    pub fn find_next_match(
14494        &mut self,
14495        _: &FindNextMatch,
14496        window: &mut Window,
14497        cx: &mut Context<Self>,
14498    ) -> Result<()> {
14499        let selections = self.selections.disjoint_anchors();
14500        match selections.first() {
14501            Some(first) if selections.len() >= 2 => {
14502                self.change_selections(Default::default(), window, cx, |s| {
14503                    s.select_ranges([first.range()]);
14504                });
14505            }
14506            _ => self.select_next(
14507                &SelectNext {
14508                    replace_newest: true,
14509                },
14510                window,
14511                cx,
14512            )?,
14513        }
14514        Ok(())
14515    }
14516
14517    pub fn find_previous_match(
14518        &mut self,
14519        _: &FindPreviousMatch,
14520        window: &mut Window,
14521        cx: &mut Context<Self>,
14522    ) -> Result<()> {
14523        let selections = self.selections.disjoint_anchors();
14524        match selections.last() {
14525            Some(last) if selections.len() >= 2 => {
14526                self.change_selections(Default::default(), window, cx, |s| {
14527                    s.select_ranges([last.range()]);
14528                });
14529            }
14530            _ => self.select_previous(
14531                &SelectPrevious {
14532                    replace_newest: true,
14533                },
14534                window,
14535                cx,
14536            )?,
14537        }
14538        Ok(())
14539    }
14540
14541    pub fn toggle_comments(
14542        &mut self,
14543        action: &ToggleComments,
14544        window: &mut Window,
14545        cx: &mut Context<Self>,
14546    ) {
14547        if self.read_only(cx) {
14548            return;
14549        }
14550        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14551        let text_layout_details = &self.text_layout_details(window);
14552        self.transact(window, cx, |this, window, cx| {
14553            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14554            let mut edits = Vec::new();
14555            let mut selection_edit_ranges = Vec::new();
14556            let mut last_toggled_row = None;
14557            let snapshot = this.buffer.read(cx).read(cx);
14558            let empty_str: Arc<str> = Arc::default();
14559            let mut suffixes_inserted = Vec::new();
14560            let ignore_indent = action.ignore_indent;
14561
14562            fn comment_prefix_range(
14563                snapshot: &MultiBufferSnapshot,
14564                row: MultiBufferRow,
14565                comment_prefix: &str,
14566                comment_prefix_whitespace: &str,
14567                ignore_indent: bool,
14568            ) -> Range<Point> {
14569                let indent_size = if ignore_indent {
14570                    0
14571                } else {
14572                    snapshot.indent_size_for_line(row).len
14573                };
14574
14575                let start = Point::new(row.0, indent_size);
14576
14577                let mut line_bytes = snapshot
14578                    .bytes_in_range(start..snapshot.max_point())
14579                    .flatten()
14580                    .copied();
14581
14582                // If this line currently begins with the line comment prefix, then record
14583                // the range containing the prefix.
14584                if line_bytes
14585                    .by_ref()
14586                    .take(comment_prefix.len())
14587                    .eq(comment_prefix.bytes())
14588                {
14589                    // Include any whitespace that matches the comment prefix.
14590                    let matching_whitespace_len = line_bytes
14591                        .zip(comment_prefix_whitespace.bytes())
14592                        .take_while(|(a, b)| a == b)
14593                        .count() as u32;
14594                    let end = Point::new(
14595                        start.row,
14596                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14597                    );
14598                    start..end
14599                } else {
14600                    start..start
14601                }
14602            }
14603
14604            fn comment_suffix_range(
14605                snapshot: &MultiBufferSnapshot,
14606                row: MultiBufferRow,
14607                comment_suffix: &str,
14608                comment_suffix_has_leading_space: bool,
14609            ) -> Range<Point> {
14610                let end = Point::new(row.0, snapshot.line_len(row));
14611                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14612
14613                let mut line_end_bytes = snapshot
14614                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14615                    .flatten()
14616                    .copied();
14617
14618                let leading_space_len = if suffix_start_column > 0
14619                    && line_end_bytes.next() == Some(b' ')
14620                    && comment_suffix_has_leading_space
14621                {
14622                    1
14623                } else {
14624                    0
14625                };
14626
14627                // If this line currently begins with the line comment prefix, then record
14628                // the range containing the prefix.
14629                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14630                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14631                    start..end
14632                } else {
14633                    end..end
14634                }
14635            }
14636
14637            // TODO: Handle selections that cross excerpts
14638            for selection in &mut selections {
14639                let start_column = snapshot
14640                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14641                    .len;
14642                let language = if let Some(language) =
14643                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14644                {
14645                    language
14646                } else {
14647                    continue;
14648                };
14649
14650                selection_edit_ranges.clear();
14651
14652                // If multiple selections contain a given row, avoid processing that
14653                // row more than once.
14654                let mut start_row = MultiBufferRow(selection.start.row);
14655                if last_toggled_row == Some(start_row) {
14656                    start_row = start_row.next_row();
14657                }
14658                let end_row =
14659                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14660                        MultiBufferRow(selection.end.row - 1)
14661                    } else {
14662                        MultiBufferRow(selection.end.row)
14663                    };
14664                last_toggled_row = Some(end_row);
14665
14666                if start_row > end_row {
14667                    continue;
14668                }
14669
14670                // If the language has line comments, toggle those.
14671                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14672
14673                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14674                if ignore_indent {
14675                    full_comment_prefixes = full_comment_prefixes
14676                        .into_iter()
14677                        .map(|s| Arc::from(s.trim_end()))
14678                        .collect();
14679                }
14680
14681                if !full_comment_prefixes.is_empty() {
14682                    let first_prefix = full_comment_prefixes
14683                        .first()
14684                        .expect("prefixes is non-empty");
14685                    let prefix_trimmed_lengths = full_comment_prefixes
14686                        .iter()
14687                        .map(|p| p.trim_end_matches(' ').len())
14688                        .collect::<SmallVec<[usize; 4]>>();
14689
14690                    let mut all_selection_lines_are_comments = true;
14691
14692                    for row in start_row.0..=end_row.0 {
14693                        let row = MultiBufferRow(row);
14694                        if start_row < end_row && snapshot.is_line_blank(row) {
14695                            continue;
14696                        }
14697
14698                        let prefix_range = full_comment_prefixes
14699                            .iter()
14700                            .zip(prefix_trimmed_lengths.iter().copied())
14701                            .map(|(prefix, trimmed_prefix_len)| {
14702                                comment_prefix_range(
14703                                    snapshot.deref(),
14704                                    row,
14705                                    &prefix[..trimmed_prefix_len],
14706                                    &prefix[trimmed_prefix_len..],
14707                                    ignore_indent,
14708                                )
14709                            })
14710                            .max_by_key(|range| range.end.column - range.start.column)
14711                            .expect("prefixes is non-empty");
14712
14713                        if prefix_range.is_empty() {
14714                            all_selection_lines_are_comments = false;
14715                        }
14716
14717                        selection_edit_ranges.push(prefix_range);
14718                    }
14719
14720                    if all_selection_lines_are_comments {
14721                        edits.extend(
14722                            selection_edit_ranges
14723                                .iter()
14724                                .cloned()
14725                                .map(|range| (range, empty_str.clone())),
14726                        );
14727                    } else {
14728                        let min_column = selection_edit_ranges
14729                            .iter()
14730                            .map(|range| range.start.column)
14731                            .min()
14732                            .unwrap_or(0);
14733                        edits.extend(selection_edit_ranges.iter().map(|range| {
14734                            let position = Point::new(range.start.row, min_column);
14735                            (position..position, first_prefix.clone())
14736                        }));
14737                    }
14738                } else if let Some(BlockCommentConfig {
14739                    start: full_comment_prefix,
14740                    end: comment_suffix,
14741                    ..
14742                }) = language.block_comment()
14743                {
14744                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14745                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14746                    let prefix_range = comment_prefix_range(
14747                        snapshot.deref(),
14748                        start_row,
14749                        comment_prefix,
14750                        comment_prefix_whitespace,
14751                        ignore_indent,
14752                    );
14753                    let suffix_range = comment_suffix_range(
14754                        snapshot.deref(),
14755                        end_row,
14756                        comment_suffix.trim_start_matches(' '),
14757                        comment_suffix.starts_with(' '),
14758                    );
14759
14760                    if prefix_range.is_empty() || suffix_range.is_empty() {
14761                        edits.push((
14762                            prefix_range.start..prefix_range.start,
14763                            full_comment_prefix.clone(),
14764                        ));
14765                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14766                        suffixes_inserted.push((end_row, comment_suffix.len()));
14767                    } else {
14768                        edits.push((prefix_range, empty_str.clone()));
14769                        edits.push((suffix_range, empty_str.clone()));
14770                    }
14771                } else {
14772                    continue;
14773                }
14774            }
14775
14776            drop(snapshot);
14777            this.buffer.update(cx, |buffer, cx| {
14778                buffer.edit(edits, None, cx);
14779            });
14780
14781            // Adjust selections so that they end before any comment suffixes that
14782            // were inserted.
14783            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14784            let mut selections = this.selections.all::<Point>(cx);
14785            let snapshot = this.buffer.read(cx).read(cx);
14786            for selection in &mut selections {
14787                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14788                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14789                        Ordering::Less => {
14790                            suffixes_inserted.next();
14791                            continue;
14792                        }
14793                        Ordering::Greater => break,
14794                        Ordering::Equal => {
14795                            if selection.end.column == snapshot.line_len(row) {
14796                                if selection.is_empty() {
14797                                    selection.start.column -= suffix_len as u32;
14798                                }
14799                                selection.end.column -= suffix_len as u32;
14800                            }
14801                            break;
14802                        }
14803                    }
14804                }
14805            }
14806
14807            drop(snapshot);
14808            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14809
14810            let selections = this.selections.all::<Point>(cx);
14811            let selections_on_single_row = selections.windows(2).all(|selections| {
14812                selections[0].start.row == selections[1].start.row
14813                    && selections[0].end.row == selections[1].end.row
14814                    && selections[0].start.row == selections[0].end.row
14815            });
14816            let selections_selecting = selections
14817                .iter()
14818                .any(|selection| selection.start != selection.end);
14819            let advance_downwards = action.advance_downwards
14820                && selections_on_single_row
14821                && !selections_selecting
14822                && !matches!(this.mode, EditorMode::SingleLine);
14823
14824            if advance_downwards {
14825                let snapshot = this.buffer.read(cx).snapshot(cx);
14826
14827                this.change_selections(Default::default(), window, cx, |s| {
14828                    s.move_cursors_with(|display_snapshot, display_point, _| {
14829                        let mut point = display_point.to_point(display_snapshot);
14830                        point.row += 1;
14831                        point = snapshot.clip_point(point, Bias::Left);
14832                        let display_point = point.to_display_point(display_snapshot);
14833                        let goal = SelectionGoal::HorizontalPosition(
14834                            display_snapshot
14835                                .x_for_display_point(display_point, text_layout_details)
14836                                .into(),
14837                        );
14838                        (display_point, goal)
14839                    })
14840                });
14841            }
14842        });
14843    }
14844
14845    pub fn select_enclosing_symbol(
14846        &mut self,
14847        _: &SelectEnclosingSymbol,
14848        window: &mut Window,
14849        cx: &mut Context<Self>,
14850    ) {
14851        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14852
14853        let buffer = self.buffer.read(cx).snapshot(cx);
14854        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14855
14856        fn update_selection(
14857            selection: &Selection<usize>,
14858            buffer_snap: &MultiBufferSnapshot,
14859        ) -> Option<Selection<usize>> {
14860            let cursor = selection.head();
14861            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14862            for symbol in symbols.iter().rev() {
14863                let start = symbol.range.start.to_offset(buffer_snap);
14864                let end = symbol.range.end.to_offset(buffer_snap);
14865                let new_range = start..end;
14866                if start < selection.start || end > selection.end {
14867                    return Some(Selection {
14868                        id: selection.id,
14869                        start: new_range.start,
14870                        end: new_range.end,
14871                        goal: SelectionGoal::None,
14872                        reversed: selection.reversed,
14873                    });
14874                }
14875            }
14876            None
14877        }
14878
14879        let mut selected_larger_symbol = false;
14880        let new_selections = old_selections
14881            .iter()
14882            .map(|selection| match update_selection(selection, &buffer) {
14883                Some(new_selection) => {
14884                    if new_selection.range() != selection.range() {
14885                        selected_larger_symbol = true;
14886                    }
14887                    new_selection
14888                }
14889                None => selection.clone(),
14890            })
14891            .collect::<Vec<_>>();
14892
14893        if selected_larger_symbol {
14894            self.change_selections(Default::default(), window, cx, |s| {
14895                s.select(new_selections);
14896            });
14897        }
14898    }
14899
14900    pub fn select_larger_syntax_node(
14901        &mut self,
14902        _: &SelectLargerSyntaxNode,
14903        window: &mut Window,
14904        cx: &mut Context<Self>,
14905    ) {
14906        let Some(visible_row_count) = self.visible_row_count() else {
14907            return;
14908        };
14909        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14910        if old_selections.is_empty() {
14911            return;
14912        }
14913
14914        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14915
14916        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14917        let buffer = self.buffer.read(cx).snapshot(cx);
14918
14919        let mut selected_larger_node = false;
14920        let mut new_selections = old_selections
14921            .iter()
14922            .map(|selection| {
14923                let old_range = selection.start..selection.end;
14924
14925                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14926                    // manually select word at selection
14927                    if ["string_content", "inline"].contains(&node.kind()) {
14928                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14929                        // ignore if word is already selected
14930                        if !word_range.is_empty() && old_range != word_range {
14931                            let (last_word_range, _) =
14932                                buffer.surrounding_word(old_range.end, false);
14933                            // only select word if start and end point belongs to same word
14934                            if word_range == last_word_range {
14935                                selected_larger_node = true;
14936                                return Selection {
14937                                    id: selection.id,
14938                                    start: word_range.start,
14939                                    end: word_range.end,
14940                                    goal: SelectionGoal::None,
14941                                    reversed: selection.reversed,
14942                                };
14943                            }
14944                        }
14945                    }
14946                }
14947
14948                let mut new_range = old_range.clone();
14949                while let Some((_node, containing_range)) =
14950                    buffer.syntax_ancestor(new_range.clone())
14951                {
14952                    new_range = match containing_range {
14953                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14954                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14955                    };
14956                    if !display_map.intersects_fold(new_range.start)
14957                        && !display_map.intersects_fold(new_range.end)
14958                    {
14959                        break;
14960                    }
14961                }
14962
14963                selected_larger_node |= new_range != old_range;
14964                Selection {
14965                    id: selection.id,
14966                    start: new_range.start,
14967                    end: new_range.end,
14968                    goal: SelectionGoal::None,
14969                    reversed: selection.reversed,
14970                }
14971            })
14972            .collect::<Vec<_>>();
14973
14974        if !selected_larger_node {
14975            return; // don't put this call in the history
14976        }
14977
14978        // scroll based on transformation done to the last selection created by the user
14979        let (last_old, last_new) = old_selections
14980            .last()
14981            .zip(new_selections.last().cloned())
14982            .expect("old_selections isn't empty");
14983
14984        // revert selection
14985        let is_selection_reversed = {
14986            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14987            new_selections.last_mut().expect("checked above").reversed =
14988                should_newest_selection_be_reversed;
14989            should_newest_selection_be_reversed
14990        };
14991
14992        if selected_larger_node {
14993            self.select_syntax_node_history.disable_clearing = true;
14994            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14995                s.select(new_selections.clone());
14996            });
14997            self.select_syntax_node_history.disable_clearing = false;
14998        }
14999
15000        let start_row = last_new.start.to_display_point(&display_map).row().0;
15001        let end_row = last_new.end.to_display_point(&display_map).row().0;
15002        let selection_height = end_row - start_row + 1;
15003        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15004
15005        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15006        let scroll_behavior = if fits_on_the_screen {
15007            self.request_autoscroll(Autoscroll::fit(), cx);
15008            SelectSyntaxNodeScrollBehavior::FitSelection
15009        } else if is_selection_reversed {
15010            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15011            SelectSyntaxNodeScrollBehavior::CursorTop
15012        } else {
15013            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15014            SelectSyntaxNodeScrollBehavior::CursorBottom
15015        };
15016
15017        self.select_syntax_node_history.push((
15018            old_selections,
15019            scroll_behavior,
15020            is_selection_reversed,
15021        ));
15022    }
15023
15024    pub fn select_smaller_syntax_node(
15025        &mut self,
15026        _: &SelectSmallerSyntaxNode,
15027        window: &mut Window,
15028        cx: &mut Context<Self>,
15029    ) {
15030        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15031
15032        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15033            self.select_syntax_node_history.pop()
15034        {
15035            if let Some(selection) = selections.last_mut() {
15036                selection.reversed = is_selection_reversed;
15037            }
15038
15039            self.select_syntax_node_history.disable_clearing = true;
15040            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15041                s.select(selections.to_vec());
15042            });
15043            self.select_syntax_node_history.disable_clearing = false;
15044
15045            match scroll_behavior {
15046                SelectSyntaxNodeScrollBehavior::CursorTop => {
15047                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15048                }
15049                SelectSyntaxNodeScrollBehavior::FitSelection => {
15050                    self.request_autoscroll(Autoscroll::fit(), cx);
15051                }
15052                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15053                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15054                }
15055            }
15056        }
15057    }
15058
15059    pub fn unwrap_syntax_node(
15060        &mut self,
15061        _: &UnwrapSyntaxNode,
15062        window: &mut Window,
15063        cx: &mut Context<Self>,
15064    ) {
15065        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15066
15067        let buffer = self.buffer.read(cx).snapshot(cx);
15068        let selections = self
15069            .selections
15070            .all::<usize>(cx)
15071            .into_iter()
15072            // subtracting the offset requires sorting
15073            .sorted_by_key(|i| i.start);
15074
15075        let full_edits = selections
15076            .into_iter()
15077            .filter_map(|selection| {
15078                // Only requires two branches once if-let-chains stabilize (#53667)
15079                let child = if !selection.is_empty() {
15080                    selection.range()
15081                } else if let Some((_, ancestor_range)) =
15082                    buffer.syntax_ancestor(selection.start..selection.end)
15083                {
15084                    match ancestor_range {
15085                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15086                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15087                    }
15088                } else {
15089                    selection.range()
15090                };
15091
15092                let mut parent = child.clone();
15093                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15094                    parent = match ancestor_range {
15095                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15096                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15097                    };
15098                    if parent.start < child.start || parent.end > child.end {
15099                        break;
15100                    }
15101                }
15102
15103                if parent == child {
15104                    return None;
15105                }
15106                let text = buffer.text_for_range(child).collect::<String>();
15107                Some((selection.id, parent, text))
15108            })
15109            .collect::<Vec<_>>();
15110
15111        self.transact(window, cx, |this, window, cx| {
15112            this.buffer.update(cx, |buffer, cx| {
15113                buffer.edit(
15114                    full_edits
15115                        .iter()
15116                        .map(|(_, p, t)| (p.clone(), t.clone()))
15117                        .collect::<Vec<_>>(),
15118                    None,
15119                    cx,
15120                );
15121            });
15122            this.change_selections(Default::default(), window, cx, |s| {
15123                let mut offset = 0;
15124                let mut selections = vec![];
15125                for (id, parent, text) in full_edits {
15126                    let start = parent.start - offset;
15127                    offset += parent.len() - text.len();
15128                    selections.push(Selection {
15129                        id,
15130                        start,
15131                        end: start + text.len(),
15132                        reversed: false,
15133                        goal: Default::default(),
15134                    });
15135                }
15136                s.select(selections);
15137            });
15138        });
15139    }
15140
15141    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15142        if !EditorSettings::get_global(cx).gutter.runnables {
15143            self.clear_tasks();
15144            return Task::ready(());
15145        }
15146        let project = self.project().map(Entity::downgrade);
15147        let task_sources = self.lsp_task_sources(cx);
15148        let multi_buffer = self.buffer.downgrade();
15149        cx.spawn_in(window, async move |editor, cx| {
15150            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15151            let Some(project) = project.and_then(|p| p.upgrade()) else {
15152                return;
15153            };
15154            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15155                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15156            }) else {
15157                return;
15158            };
15159
15160            let hide_runnables = project
15161                .update(cx, |project, _| project.is_via_collab())
15162                .unwrap_or(true);
15163            if hide_runnables {
15164                return;
15165            }
15166            let new_rows =
15167                cx.background_spawn({
15168                    let snapshot = display_snapshot.clone();
15169                    async move {
15170                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15171                    }
15172                })
15173                    .await;
15174            let Ok(lsp_tasks) =
15175                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15176            else {
15177                return;
15178            };
15179            let lsp_tasks = lsp_tasks.await;
15180
15181            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15182                lsp_tasks
15183                    .into_iter()
15184                    .flat_map(|(kind, tasks)| {
15185                        tasks.into_iter().filter_map(move |(location, task)| {
15186                            Some((kind.clone(), location?, task))
15187                        })
15188                    })
15189                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15190                        let buffer = location.target.buffer;
15191                        let buffer_snapshot = buffer.read(cx).snapshot();
15192                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15193                            |(excerpt_id, snapshot, _)| {
15194                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15195                                    display_snapshot
15196                                        .buffer_snapshot
15197                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15198                                } else {
15199                                    None
15200                                }
15201                            },
15202                        );
15203                        if let Some(offset) = offset {
15204                            let task_buffer_range =
15205                                location.target.range.to_point(&buffer_snapshot);
15206                            let context_buffer_range =
15207                                task_buffer_range.to_offset(&buffer_snapshot);
15208                            let context_range = BufferOffset(context_buffer_range.start)
15209                                ..BufferOffset(context_buffer_range.end);
15210
15211                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15212                                .or_insert_with(|| RunnableTasks {
15213                                    templates: Vec::new(),
15214                                    offset,
15215                                    column: task_buffer_range.start.column,
15216                                    extra_variables: HashMap::default(),
15217                                    context_range,
15218                                })
15219                                .templates
15220                                .push((kind, task.original_task().clone()));
15221                        }
15222
15223                        acc
15224                    })
15225            }) else {
15226                return;
15227            };
15228
15229            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15230                buffer.language_settings(cx).tasks.prefer_lsp
15231            }) else {
15232                return;
15233            };
15234
15235            let rows = Self::runnable_rows(
15236                project,
15237                display_snapshot,
15238                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15239                new_rows,
15240                cx.clone(),
15241            )
15242            .await;
15243            editor
15244                .update(cx, |editor, _| {
15245                    editor.clear_tasks();
15246                    for (key, mut value) in rows {
15247                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15248                            value.templates.extend(lsp_tasks.templates);
15249                        }
15250
15251                        editor.insert_tasks(key, value);
15252                    }
15253                    for (key, value) in lsp_tasks_by_rows {
15254                        editor.insert_tasks(key, value);
15255                    }
15256                })
15257                .ok();
15258        })
15259    }
15260    fn fetch_runnable_ranges(
15261        snapshot: &DisplaySnapshot,
15262        range: Range<Anchor>,
15263    ) -> Vec<language::RunnableRange> {
15264        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15265    }
15266
15267    fn runnable_rows(
15268        project: Entity<Project>,
15269        snapshot: DisplaySnapshot,
15270        prefer_lsp: bool,
15271        runnable_ranges: Vec<RunnableRange>,
15272        cx: AsyncWindowContext,
15273    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15274        cx.spawn(async move |cx| {
15275            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15276            for mut runnable in runnable_ranges {
15277                let Some(tasks) = cx
15278                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15279                    .ok()
15280                else {
15281                    continue;
15282                };
15283                let mut tasks = tasks.await;
15284
15285                if prefer_lsp {
15286                    tasks.retain(|(task_kind, _)| {
15287                        !matches!(task_kind, TaskSourceKind::Language { .. })
15288                    });
15289                }
15290                if tasks.is_empty() {
15291                    continue;
15292                }
15293
15294                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15295                let Some(row) = snapshot
15296                    .buffer_snapshot
15297                    .buffer_line_for_row(MultiBufferRow(point.row))
15298                    .map(|(_, range)| range.start.row)
15299                else {
15300                    continue;
15301                };
15302
15303                let context_range =
15304                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15305                runnable_rows.push((
15306                    (runnable.buffer_id, row),
15307                    RunnableTasks {
15308                        templates: tasks,
15309                        offset: snapshot
15310                            .buffer_snapshot
15311                            .anchor_before(runnable.run_range.start),
15312                        context_range,
15313                        column: point.column,
15314                        extra_variables: runnable.extra_captures,
15315                    },
15316                ));
15317            }
15318            runnable_rows
15319        })
15320    }
15321
15322    fn templates_with_tags(
15323        project: &Entity<Project>,
15324        runnable: &mut Runnable,
15325        cx: &mut App,
15326    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15327        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15328            let (worktree_id, file) = project
15329                .buffer_for_id(runnable.buffer, cx)
15330                .and_then(|buffer| buffer.read(cx).file())
15331                .map(|file| (file.worktree_id(cx), file.clone()))
15332                .unzip();
15333
15334            (
15335                project.task_store().read(cx).task_inventory().cloned(),
15336                worktree_id,
15337                file,
15338            )
15339        });
15340
15341        let tags = mem::take(&mut runnable.tags);
15342        let language = runnable.language.clone();
15343        cx.spawn(async move |cx| {
15344            let mut templates_with_tags = Vec::new();
15345            if let Some(inventory) = inventory {
15346                for RunnableTag(tag) in tags {
15347                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15348                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15349                    }) else {
15350                        return templates_with_tags;
15351                    };
15352                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15353                        move |(_, template)| {
15354                            template.tags.iter().any(|source_tag| source_tag == &tag)
15355                        },
15356                    ));
15357                }
15358            }
15359            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15360
15361            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15362                // Strongest source wins; if we have worktree tag binding, prefer that to
15363                // global and language bindings;
15364                // if we have a global binding, prefer that to language binding.
15365                let first_mismatch = templates_with_tags
15366                    .iter()
15367                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15368                if let Some(index) = first_mismatch {
15369                    templates_with_tags.truncate(index);
15370                }
15371            }
15372
15373            templates_with_tags
15374        })
15375    }
15376
15377    pub fn move_to_enclosing_bracket(
15378        &mut self,
15379        _: &MoveToEnclosingBracket,
15380        window: &mut Window,
15381        cx: &mut Context<Self>,
15382    ) {
15383        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15384        self.change_selections(Default::default(), window, cx, |s| {
15385            s.move_offsets_with(|snapshot, selection| {
15386                let Some(enclosing_bracket_ranges) =
15387                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15388                else {
15389                    return;
15390                };
15391
15392                let mut best_length = usize::MAX;
15393                let mut best_inside = false;
15394                let mut best_in_bracket_range = false;
15395                let mut best_destination = None;
15396                for (open, close) in enclosing_bracket_ranges {
15397                    let close = close.to_inclusive();
15398                    let length = close.end() - open.start;
15399                    let inside = selection.start >= open.end && selection.end <= *close.start();
15400                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15401                        || close.contains(&selection.head());
15402
15403                    // If best is next to a bracket and current isn't, skip
15404                    if !in_bracket_range && best_in_bracket_range {
15405                        continue;
15406                    }
15407
15408                    // Prefer smaller lengths unless best is inside and current isn't
15409                    if length > best_length && (best_inside || !inside) {
15410                        continue;
15411                    }
15412
15413                    best_length = length;
15414                    best_inside = inside;
15415                    best_in_bracket_range = in_bracket_range;
15416                    best_destination = Some(
15417                        if close.contains(&selection.start) && close.contains(&selection.end) {
15418                            if inside { open.end } else { open.start }
15419                        } else if inside {
15420                            *close.start()
15421                        } else {
15422                            *close.end()
15423                        },
15424                    );
15425                }
15426
15427                if let Some(destination) = best_destination {
15428                    selection.collapse_to(destination, SelectionGoal::None);
15429                }
15430            })
15431        });
15432    }
15433
15434    pub fn undo_selection(
15435        &mut self,
15436        _: &UndoSelection,
15437        window: &mut Window,
15438        cx: &mut Context<Self>,
15439    ) {
15440        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15441        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15442            self.selection_history.mode = SelectionHistoryMode::Undoing;
15443            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15444                this.end_selection(window, cx);
15445                this.change_selections(
15446                    SelectionEffects::scroll(Autoscroll::newest()),
15447                    window,
15448                    cx,
15449                    |s| s.select_anchors(entry.selections.to_vec()),
15450                );
15451            });
15452            self.selection_history.mode = SelectionHistoryMode::Normal;
15453
15454            self.select_next_state = entry.select_next_state;
15455            self.select_prev_state = entry.select_prev_state;
15456            self.add_selections_state = entry.add_selections_state;
15457        }
15458    }
15459
15460    pub fn redo_selection(
15461        &mut self,
15462        _: &RedoSelection,
15463        window: &mut Window,
15464        cx: &mut Context<Self>,
15465    ) {
15466        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15467        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15468            self.selection_history.mode = SelectionHistoryMode::Redoing;
15469            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15470                this.end_selection(window, cx);
15471                this.change_selections(
15472                    SelectionEffects::scroll(Autoscroll::newest()),
15473                    window,
15474                    cx,
15475                    |s| s.select_anchors(entry.selections.to_vec()),
15476                );
15477            });
15478            self.selection_history.mode = SelectionHistoryMode::Normal;
15479
15480            self.select_next_state = entry.select_next_state;
15481            self.select_prev_state = entry.select_prev_state;
15482            self.add_selections_state = entry.add_selections_state;
15483        }
15484    }
15485
15486    pub fn expand_excerpts(
15487        &mut self,
15488        action: &ExpandExcerpts,
15489        _: &mut Window,
15490        cx: &mut Context<Self>,
15491    ) {
15492        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15493    }
15494
15495    pub fn expand_excerpts_down(
15496        &mut self,
15497        action: &ExpandExcerptsDown,
15498        _: &mut Window,
15499        cx: &mut Context<Self>,
15500    ) {
15501        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15502    }
15503
15504    pub fn expand_excerpts_up(
15505        &mut self,
15506        action: &ExpandExcerptsUp,
15507        _: &mut Window,
15508        cx: &mut Context<Self>,
15509    ) {
15510        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15511    }
15512
15513    pub fn expand_excerpts_for_direction(
15514        &mut self,
15515        lines: u32,
15516        direction: ExpandExcerptDirection,
15517
15518        cx: &mut Context<Self>,
15519    ) {
15520        let selections = self.selections.disjoint_anchors();
15521
15522        let lines = if lines == 0 {
15523            EditorSettings::get_global(cx).expand_excerpt_lines
15524        } else {
15525            lines
15526        };
15527
15528        self.buffer.update(cx, |buffer, cx| {
15529            let snapshot = buffer.snapshot(cx);
15530            let mut excerpt_ids = selections
15531                .iter()
15532                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15533                .collect::<Vec<_>>();
15534            excerpt_ids.sort();
15535            excerpt_ids.dedup();
15536            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15537        })
15538    }
15539
15540    pub fn expand_excerpt(
15541        &mut self,
15542        excerpt: ExcerptId,
15543        direction: ExpandExcerptDirection,
15544        window: &mut Window,
15545        cx: &mut Context<Self>,
15546    ) {
15547        let current_scroll_position = self.scroll_position(cx);
15548        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15549        let mut should_scroll_up = false;
15550
15551        if direction == ExpandExcerptDirection::Down {
15552            let multi_buffer = self.buffer.read(cx);
15553            let snapshot = multi_buffer.snapshot(cx);
15554            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15555                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15556                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15557            {
15558                let buffer_snapshot = buffer.read(cx).snapshot();
15559                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15560                let last_row = buffer_snapshot.max_point().row;
15561                let lines_below = last_row.saturating_sub(excerpt_end_row);
15562                should_scroll_up = lines_below >= lines_to_expand;
15563            }
15564        }
15565
15566        self.buffer.update(cx, |buffer, cx| {
15567            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15568        });
15569
15570        if should_scroll_up {
15571            let new_scroll_position =
15572                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15573            self.set_scroll_position(new_scroll_position, window, cx);
15574        }
15575    }
15576
15577    pub fn go_to_singleton_buffer_point(
15578        &mut self,
15579        point: Point,
15580        window: &mut Window,
15581        cx: &mut Context<Self>,
15582    ) {
15583        self.go_to_singleton_buffer_range(point..point, window, cx);
15584    }
15585
15586    pub fn go_to_singleton_buffer_range(
15587        &mut self,
15588        range: Range<Point>,
15589        window: &mut Window,
15590        cx: &mut Context<Self>,
15591    ) {
15592        let multibuffer = self.buffer().read(cx);
15593        let Some(buffer) = multibuffer.as_singleton() else {
15594            return;
15595        };
15596        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15597            return;
15598        };
15599        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15600            return;
15601        };
15602        self.change_selections(
15603            SelectionEffects::default().nav_history(true),
15604            window,
15605            cx,
15606            |s| s.select_anchor_ranges([start..end]),
15607        );
15608    }
15609
15610    pub fn go_to_diagnostic(
15611        &mut self,
15612        action: &GoToDiagnostic,
15613        window: &mut Window,
15614        cx: &mut Context<Self>,
15615    ) {
15616        if !self.diagnostics_enabled() {
15617            return;
15618        }
15619        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15620        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15621    }
15622
15623    pub fn go_to_prev_diagnostic(
15624        &mut self,
15625        action: &GoToPreviousDiagnostic,
15626        window: &mut Window,
15627        cx: &mut Context<Self>,
15628    ) {
15629        if !self.diagnostics_enabled() {
15630            return;
15631        }
15632        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15633        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15634    }
15635
15636    pub fn go_to_diagnostic_impl(
15637        &mut self,
15638        direction: Direction,
15639        severity: GoToDiagnosticSeverityFilter,
15640        window: &mut Window,
15641        cx: &mut Context<Self>,
15642    ) {
15643        let buffer = self.buffer.read(cx).snapshot(cx);
15644        let selection = self.selections.newest::<usize>(cx);
15645
15646        let mut active_group_id = None;
15647        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15648            && active_group.active_range.start.to_offset(&buffer) == selection.start
15649        {
15650            active_group_id = Some(active_group.group_id);
15651        }
15652
15653        fn filtered(
15654            snapshot: EditorSnapshot,
15655            severity: GoToDiagnosticSeverityFilter,
15656            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15657        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15658            diagnostics
15659                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15660                .filter(|entry| entry.range.start != entry.range.end)
15661                .filter(|entry| !entry.diagnostic.is_unnecessary)
15662                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15663        }
15664
15665        let snapshot = self.snapshot(window, cx);
15666        let before = filtered(
15667            snapshot.clone(),
15668            severity,
15669            buffer
15670                .diagnostics_in_range(0..selection.start)
15671                .filter(|entry| entry.range.start <= selection.start),
15672        );
15673        let after = filtered(
15674            snapshot,
15675            severity,
15676            buffer
15677                .diagnostics_in_range(selection.start..buffer.len())
15678                .filter(|entry| entry.range.start >= selection.start),
15679        );
15680
15681        let mut found: Option<DiagnosticEntry<usize>> = None;
15682        if direction == Direction::Prev {
15683            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15684            {
15685                for diagnostic in prev_diagnostics.into_iter().rev() {
15686                    if diagnostic.range.start != selection.start
15687                        || active_group_id
15688                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15689                    {
15690                        found = Some(diagnostic);
15691                        break 'outer;
15692                    }
15693                }
15694            }
15695        } else {
15696            for diagnostic in after.chain(before) {
15697                if diagnostic.range.start != selection.start
15698                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15699                {
15700                    found = Some(diagnostic);
15701                    break;
15702                }
15703            }
15704        }
15705        let Some(next_diagnostic) = found else {
15706            return;
15707        };
15708
15709        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15710        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15711            return;
15712        };
15713        self.change_selections(Default::default(), window, cx, |s| {
15714            s.select_ranges(vec![
15715                next_diagnostic.range.start..next_diagnostic.range.start,
15716            ])
15717        });
15718        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15719        self.refresh_edit_prediction(false, true, window, cx);
15720    }
15721
15722    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15723        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15724        let snapshot = self.snapshot(window, cx);
15725        let selection = self.selections.newest::<Point>(cx);
15726        self.go_to_hunk_before_or_after_position(
15727            &snapshot,
15728            selection.head(),
15729            Direction::Next,
15730            window,
15731            cx,
15732        );
15733    }
15734
15735    pub fn go_to_hunk_before_or_after_position(
15736        &mut self,
15737        snapshot: &EditorSnapshot,
15738        position: Point,
15739        direction: Direction,
15740        window: &mut Window,
15741        cx: &mut Context<Editor>,
15742    ) {
15743        let row = if direction == Direction::Next {
15744            self.hunk_after_position(snapshot, position)
15745                .map(|hunk| hunk.row_range.start)
15746        } else {
15747            self.hunk_before_position(snapshot, position)
15748        };
15749
15750        if let Some(row) = row {
15751            let destination = Point::new(row.0, 0);
15752            let autoscroll = Autoscroll::center();
15753
15754            self.unfold_ranges(&[destination..destination], false, false, cx);
15755            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15756                s.select_ranges([destination..destination]);
15757            });
15758        }
15759    }
15760
15761    fn hunk_after_position(
15762        &mut self,
15763        snapshot: &EditorSnapshot,
15764        position: Point,
15765    ) -> Option<MultiBufferDiffHunk> {
15766        snapshot
15767            .buffer_snapshot
15768            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15769            .find(|hunk| hunk.row_range.start.0 > position.row)
15770            .or_else(|| {
15771                snapshot
15772                    .buffer_snapshot
15773                    .diff_hunks_in_range(Point::zero()..position)
15774                    .find(|hunk| hunk.row_range.end.0 < position.row)
15775            })
15776    }
15777
15778    fn go_to_prev_hunk(
15779        &mut self,
15780        _: &GoToPreviousHunk,
15781        window: &mut Window,
15782        cx: &mut Context<Self>,
15783    ) {
15784        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15785        let snapshot = self.snapshot(window, cx);
15786        let selection = self.selections.newest::<Point>(cx);
15787        self.go_to_hunk_before_or_after_position(
15788            &snapshot,
15789            selection.head(),
15790            Direction::Prev,
15791            window,
15792            cx,
15793        );
15794    }
15795
15796    fn hunk_before_position(
15797        &mut self,
15798        snapshot: &EditorSnapshot,
15799        position: Point,
15800    ) -> Option<MultiBufferRow> {
15801        snapshot
15802            .buffer_snapshot
15803            .diff_hunk_before(position)
15804            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15805    }
15806
15807    fn go_to_next_change(
15808        &mut self,
15809        _: &GoToNextChange,
15810        window: &mut Window,
15811        cx: &mut Context<Self>,
15812    ) {
15813        if let Some(selections) = self
15814            .change_list
15815            .next_change(1, Direction::Next)
15816            .map(|s| s.to_vec())
15817        {
15818            self.change_selections(Default::default(), window, cx, |s| {
15819                let map = s.display_map();
15820                s.select_display_ranges(selections.iter().map(|a| {
15821                    let point = a.to_display_point(&map);
15822                    point..point
15823                }))
15824            })
15825        }
15826    }
15827
15828    fn go_to_previous_change(
15829        &mut self,
15830        _: &GoToPreviousChange,
15831        window: &mut Window,
15832        cx: &mut Context<Self>,
15833    ) {
15834        if let Some(selections) = self
15835            .change_list
15836            .next_change(1, Direction::Prev)
15837            .map(|s| s.to_vec())
15838        {
15839            self.change_selections(Default::default(), window, cx, |s| {
15840                let map = s.display_map();
15841                s.select_display_ranges(selections.iter().map(|a| {
15842                    let point = a.to_display_point(&map);
15843                    point..point
15844                }))
15845            })
15846        }
15847    }
15848
15849    fn go_to_line<T: 'static>(
15850        &mut self,
15851        position: Anchor,
15852        highlight_color: Option<Hsla>,
15853        window: &mut Window,
15854        cx: &mut Context<Self>,
15855    ) {
15856        let snapshot = self.snapshot(window, cx).display_snapshot;
15857        let position = position.to_point(&snapshot.buffer_snapshot);
15858        let start = snapshot
15859            .buffer_snapshot
15860            .clip_point(Point::new(position.row, 0), Bias::Left);
15861        let end = start + Point::new(1, 0);
15862        let start = snapshot.buffer_snapshot.anchor_before(start);
15863        let end = snapshot.buffer_snapshot.anchor_before(end);
15864
15865        self.highlight_rows::<T>(
15866            start..end,
15867            highlight_color
15868                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15869            Default::default(),
15870            cx,
15871        );
15872
15873        if self.buffer.read(cx).is_singleton() {
15874            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15875        }
15876    }
15877
15878    pub fn go_to_definition(
15879        &mut self,
15880        _: &GoToDefinition,
15881        window: &mut Window,
15882        cx: &mut Context<Self>,
15883    ) -> Task<Result<Navigated>> {
15884        let definition =
15885            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15886        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15887        cx.spawn_in(window, async move |editor, cx| {
15888            if definition.await? == Navigated::Yes {
15889                return Ok(Navigated::Yes);
15890            }
15891            match fallback_strategy {
15892                GoToDefinitionFallback::None => Ok(Navigated::No),
15893                GoToDefinitionFallback::FindAllReferences => {
15894                    match editor.update_in(cx, |editor, window, cx| {
15895                        editor.find_all_references(&FindAllReferences, window, cx)
15896                    })? {
15897                        Some(references) => references.await,
15898                        None => Ok(Navigated::No),
15899                    }
15900                }
15901            }
15902        })
15903    }
15904
15905    pub fn go_to_declaration(
15906        &mut self,
15907        _: &GoToDeclaration,
15908        window: &mut Window,
15909        cx: &mut Context<Self>,
15910    ) -> Task<Result<Navigated>> {
15911        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15912    }
15913
15914    pub fn go_to_declaration_split(
15915        &mut self,
15916        _: &GoToDeclaration,
15917        window: &mut Window,
15918        cx: &mut Context<Self>,
15919    ) -> Task<Result<Navigated>> {
15920        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15921    }
15922
15923    pub fn go_to_implementation(
15924        &mut self,
15925        _: &GoToImplementation,
15926        window: &mut Window,
15927        cx: &mut Context<Self>,
15928    ) -> Task<Result<Navigated>> {
15929        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15930    }
15931
15932    pub fn go_to_implementation_split(
15933        &mut self,
15934        _: &GoToImplementationSplit,
15935        window: &mut Window,
15936        cx: &mut Context<Self>,
15937    ) -> Task<Result<Navigated>> {
15938        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15939    }
15940
15941    pub fn go_to_type_definition(
15942        &mut self,
15943        _: &GoToTypeDefinition,
15944        window: &mut Window,
15945        cx: &mut Context<Self>,
15946    ) -> Task<Result<Navigated>> {
15947        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15948    }
15949
15950    pub fn go_to_definition_split(
15951        &mut self,
15952        _: &GoToDefinitionSplit,
15953        window: &mut Window,
15954        cx: &mut Context<Self>,
15955    ) -> Task<Result<Navigated>> {
15956        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15957    }
15958
15959    pub fn go_to_type_definition_split(
15960        &mut self,
15961        _: &GoToTypeDefinitionSplit,
15962        window: &mut Window,
15963        cx: &mut Context<Self>,
15964    ) -> Task<Result<Navigated>> {
15965        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15966    }
15967
15968    fn go_to_definition_of_kind(
15969        &mut self,
15970        kind: GotoDefinitionKind,
15971        split: bool,
15972        window: &mut Window,
15973        cx: &mut Context<Self>,
15974    ) -> Task<Result<Navigated>> {
15975        let Some(provider) = self.semantics_provider.clone() else {
15976            return Task::ready(Ok(Navigated::No));
15977        };
15978        let head = self.selections.newest::<usize>(cx).head();
15979        let buffer = self.buffer.read(cx);
15980        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15981            return Task::ready(Ok(Navigated::No));
15982        };
15983        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15984            return Task::ready(Ok(Navigated::No));
15985        };
15986
15987        cx.spawn_in(window, async move |editor, cx| {
15988            let Some(definitions) = definitions.await? else {
15989                return Ok(Navigated::No);
15990            };
15991            let navigated = editor
15992                .update_in(cx, |editor, window, cx| {
15993                    editor.navigate_to_hover_links(
15994                        Some(kind),
15995                        definitions
15996                            .into_iter()
15997                            .filter(|location| {
15998                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15999                            })
16000                            .map(HoverLink::Text)
16001                            .collect::<Vec<_>>(),
16002                        split,
16003                        window,
16004                        cx,
16005                    )
16006                })?
16007                .await?;
16008            anyhow::Ok(navigated)
16009        })
16010    }
16011
16012    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16013        let selection = self.selections.newest_anchor();
16014        let head = selection.head();
16015        let tail = selection.tail();
16016
16017        let Some((buffer, start_position)) =
16018            self.buffer.read(cx).text_anchor_for_position(head, cx)
16019        else {
16020            return;
16021        };
16022
16023        let end_position = if head != tail {
16024            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16025                return;
16026            };
16027            Some(pos)
16028        } else {
16029            None
16030        };
16031
16032        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16033            let url = if let Some(end_pos) = end_position {
16034                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16035            } else {
16036                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16037            };
16038
16039            if let Some(url) = url {
16040                editor.update(cx, |_, cx| {
16041                    cx.open_url(&url);
16042                })
16043            } else {
16044                Ok(())
16045            }
16046        });
16047
16048        url_finder.detach();
16049    }
16050
16051    pub fn open_selected_filename(
16052        &mut self,
16053        _: &OpenSelectedFilename,
16054        window: &mut Window,
16055        cx: &mut Context<Self>,
16056    ) {
16057        let Some(workspace) = self.workspace() else {
16058            return;
16059        };
16060
16061        let position = self.selections.newest_anchor().head();
16062
16063        let Some((buffer, buffer_position)) =
16064            self.buffer.read(cx).text_anchor_for_position(position, cx)
16065        else {
16066            return;
16067        };
16068
16069        let project = self.project.clone();
16070
16071        cx.spawn_in(window, async move |_, cx| {
16072            let result = find_file(&buffer, project, buffer_position, cx).await;
16073
16074            if let Some((_, path)) = result {
16075                workspace
16076                    .update_in(cx, |workspace, window, cx| {
16077                        workspace.open_resolved_path(path, window, cx)
16078                    })?
16079                    .await?;
16080            }
16081            anyhow::Ok(())
16082        })
16083        .detach();
16084    }
16085
16086    pub(crate) fn navigate_to_hover_links(
16087        &mut self,
16088        kind: Option<GotoDefinitionKind>,
16089        definitions: Vec<HoverLink>,
16090        split: bool,
16091        window: &mut Window,
16092        cx: &mut Context<Editor>,
16093    ) -> Task<Result<Navigated>> {
16094        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16095        let mut first_url_or_file = None;
16096        let definitions: Vec<_> = definitions
16097            .into_iter()
16098            .filter_map(|def| match def {
16099                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16100                HoverLink::InlayHint(lsp_location, server_id) => {
16101                    let computation =
16102                        self.compute_target_location(lsp_location, server_id, window, cx);
16103                    Some(cx.background_spawn(computation))
16104                }
16105                HoverLink::Url(url) => {
16106                    first_url_or_file = Some(Either::Left(url));
16107                    None
16108                }
16109                HoverLink::File(path) => {
16110                    first_url_or_file = Some(Either::Right(path));
16111                    None
16112                }
16113            })
16114            .collect();
16115
16116        let workspace = self.workspace();
16117
16118        cx.spawn_in(window, async move |editor, acx| {
16119            let mut locations: Vec<Location> = future::join_all(definitions)
16120                .await
16121                .into_iter()
16122                .filter_map(|location| location.transpose())
16123                .collect::<Result<_>>()
16124                .context("location tasks")?;
16125
16126            if locations.len() > 1 {
16127                let Some(workspace) = workspace else {
16128                    return Ok(Navigated::No);
16129                };
16130
16131                let tab_kind = match kind {
16132                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16133                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16134                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16135                    Some(GotoDefinitionKind::Type) => "Types",
16136                };
16137                let title = editor
16138                    .update_in(acx, |_, _, cx| {
16139                        let target = locations
16140                            .iter()
16141                            .map(|location| {
16142                                location
16143                                    .buffer
16144                                    .read(cx)
16145                                    .text_for_range(location.range.clone())
16146                                    .collect::<String>()
16147                            })
16148                            .filter(|text| !text.contains('\n'))
16149                            .unique()
16150                            .take(3)
16151                            .join(", ");
16152                        if target.is_empty() {
16153                            tab_kind.to_owned()
16154                        } else {
16155                            format!("{tab_kind} for {target}")
16156                        }
16157                    })
16158                    .context("buffer title")?;
16159
16160                let opened = workspace
16161                    .update_in(acx, |workspace, window, cx| {
16162                        Self::open_locations_in_multibuffer(
16163                            workspace,
16164                            locations,
16165                            title,
16166                            split,
16167                            MultibufferSelectionMode::First,
16168                            window,
16169                            cx,
16170                        )
16171                    })
16172                    .is_ok();
16173
16174                anyhow::Ok(Navigated::from_bool(opened))
16175            } else if locations.is_empty() {
16176                // If there is one definition, just open it directly
16177                match first_url_or_file {
16178                    Some(Either::Left(url)) => {
16179                        acx.update(|_, cx| cx.open_url(&url))?;
16180                        Ok(Navigated::Yes)
16181                    }
16182                    Some(Either::Right(path)) => {
16183                        let Some(workspace) = workspace else {
16184                            return Ok(Navigated::No);
16185                        };
16186
16187                        workspace
16188                            .update_in(acx, |workspace, window, cx| {
16189                                workspace.open_resolved_path(path, window, cx)
16190                            })?
16191                            .await?;
16192                        Ok(Navigated::Yes)
16193                    }
16194                    None => Ok(Navigated::No),
16195                }
16196            } else {
16197                let Some(workspace) = workspace else {
16198                    return Ok(Navigated::No);
16199                };
16200
16201                let target = locations.pop().unwrap();
16202                editor.update_in(acx, |editor, window, cx| {
16203                    let pane = workspace.read(cx).active_pane().clone();
16204
16205                    let range = target.range.to_point(target.buffer.read(cx));
16206                    let range = editor.range_for_match(&range);
16207                    let range = collapse_multiline_range(range);
16208
16209                    if !split
16210                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16211                    {
16212                        editor.go_to_singleton_buffer_range(range, window, cx);
16213                    } else {
16214                        window.defer(cx, move |window, cx| {
16215                            let target_editor: Entity<Self> =
16216                                workspace.update(cx, |workspace, cx| {
16217                                    let pane = if split {
16218                                        workspace.adjacent_pane(window, cx)
16219                                    } else {
16220                                        workspace.active_pane().clone()
16221                                    };
16222
16223                                    workspace.open_project_item(
16224                                        pane,
16225                                        target.buffer.clone(),
16226                                        true,
16227                                        true,
16228                                        window,
16229                                        cx,
16230                                    )
16231                                });
16232                            target_editor.update(cx, |target_editor, cx| {
16233                                // When selecting a definition in a different buffer, disable the nav history
16234                                // to avoid creating a history entry at the previous cursor location.
16235                                pane.update(cx, |pane, _| pane.disable_history());
16236                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16237                                pane.update(cx, |pane, _| pane.enable_history());
16238                            });
16239                        });
16240                    }
16241                    Navigated::Yes
16242                })
16243            }
16244        })
16245    }
16246
16247    fn compute_target_location(
16248        &self,
16249        lsp_location: lsp::Location,
16250        server_id: LanguageServerId,
16251        window: &mut Window,
16252        cx: &mut Context<Self>,
16253    ) -> Task<anyhow::Result<Option<Location>>> {
16254        let Some(project) = self.project.clone() else {
16255            return Task::ready(Ok(None));
16256        };
16257
16258        cx.spawn_in(window, async move |editor, cx| {
16259            let location_task = editor.update(cx, |_, cx| {
16260                project.update(cx, |project, cx| {
16261                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16262                })
16263            })?;
16264            let location = Some({
16265                let target_buffer_handle = location_task.await.context("open local buffer")?;
16266                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16267                    let target_start = target_buffer
16268                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16269                    let target_end = target_buffer
16270                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16271                    target_buffer.anchor_after(target_start)
16272                        ..target_buffer.anchor_before(target_end)
16273                })?;
16274                Location {
16275                    buffer: target_buffer_handle,
16276                    range,
16277                }
16278            });
16279            Ok(location)
16280        })
16281    }
16282
16283    pub fn find_all_references(
16284        &mut self,
16285        _: &FindAllReferences,
16286        window: &mut Window,
16287        cx: &mut Context<Self>,
16288    ) -> Option<Task<Result<Navigated>>> {
16289        let selection = self.selections.newest::<usize>(cx);
16290        let multi_buffer = self.buffer.read(cx);
16291        let head = selection.head();
16292
16293        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16294        let head_anchor = multi_buffer_snapshot.anchor_at(
16295            head,
16296            if head < selection.tail() {
16297                Bias::Right
16298            } else {
16299                Bias::Left
16300            },
16301        );
16302
16303        match self
16304            .find_all_references_task_sources
16305            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16306        {
16307            Ok(_) => {
16308                log::info!(
16309                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16310                );
16311                return None;
16312            }
16313            Err(i) => {
16314                self.find_all_references_task_sources.insert(i, head_anchor);
16315            }
16316        }
16317
16318        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16319        let workspace = self.workspace()?;
16320        let project = workspace.read(cx).project().clone();
16321        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16322        Some(cx.spawn_in(window, async move |editor, cx| {
16323            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16324                if let Ok(i) = editor
16325                    .find_all_references_task_sources
16326                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16327                {
16328                    editor.find_all_references_task_sources.remove(i);
16329                }
16330            });
16331
16332            let Some(locations) = references.await? else {
16333                return anyhow::Ok(Navigated::No);
16334            };
16335            if locations.is_empty() {
16336                return anyhow::Ok(Navigated::No);
16337            }
16338
16339            workspace.update_in(cx, |workspace, window, cx| {
16340                let target = locations
16341                    .iter()
16342                    .map(|location| {
16343                        location
16344                            .buffer
16345                            .read(cx)
16346                            .text_for_range(location.range.clone())
16347                            .collect::<String>()
16348                    })
16349                    .filter(|text| !text.contains('\n'))
16350                    .unique()
16351                    .take(3)
16352                    .join(", ");
16353                let title = if target.is_empty() {
16354                    "References".to_owned()
16355                } else {
16356                    format!("References to {target}")
16357                };
16358                Self::open_locations_in_multibuffer(
16359                    workspace,
16360                    locations,
16361                    title,
16362                    false,
16363                    MultibufferSelectionMode::First,
16364                    window,
16365                    cx,
16366                );
16367                Navigated::Yes
16368            })
16369        }))
16370    }
16371
16372    /// Opens a multibuffer with the given project locations in it
16373    pub fn open_locations_in_multibuffer(
16374        workspace: &mut Workspace,
16375        mut locations: Vec<Location>,
16376        title: String,
16377        split: bool,
16378        multibuffer_selection_mode: MultibufferSelectionMode,
16379        window: &mut Window,
16380        cx: &mut Context<Workspace>,
16381    ) {
16382        if locations.is_empty() {
16383            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16384            return;
16385        }
16386
16387        // If there are multiple definitions, open them in a multibuffer
16388        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16389        let mut locations = locations.into_iter().peekable();
16390        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16391        let capability = workspace.project().read(cx).capability();
16392
16393        let excerpt_buffer = cx.new(|cx| {
16394            let mut multibuffer = MultiBuffer::new(capability);
16395            while let Some(location) = locations.next() {
16396                let buffer = location.buffer.read(cx);
16397                let mut ranges_for_buffer = Vec::new();
16398                let range = location.range.to_point(buffer);
16399                ranges_for_buffer.push(range.clone());
16400
16401                while let Some(next_location) = locations.peek() {
16402                    if next_location.buffer == location.buffer {
16403                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16404                        locations.next();
16405                    } else {
16406                        break;
16407                    }
16408                }
16409
16410                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16411                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16412                    PathKey::for_buffer(&location.buffer, cx),
16413                    location.buffer.clone(),
16414                    ranges_for_buffer,
16415                    multibuffer_context_lines(cx),
16416                    cx,
16417                );
16418                ranges.extend(new_ranges)
16419            }
16420
16421            multibuffer.with_title(title)
16422        });
16423
16424        let editor = cx.new(|cx| {
16425            Editor::for_multibuffer(
16426                excerpt_buffer,
16427                Some(workspace.project().clone()),
16428                window,
16429                cx,
16430            )
16431        });
16432        editor.update(cx, |editor, cx| {
16433            match multibuffer_selection_mode {
16434                MultibufferSelectionMode::First => {
16435                    if let Some(first_range) = ranges.first() {
16436                        editor.change_selections(
16437                            SelectionEffects::no_scroll(),
16438                            window,
16439                            cx,
16440                            |selections| {
16441                                selections.clear_disjoint();
16442                                selections
16443                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16444                            },
16445                        );
16446                    }
16447                    editor.highlight_background::<Self>(
16448                        &ranges,
16449                        |theme| theme.colors().editor_highlighted_line_background,
16450                        cx,
16451                    );
16452                }
16453                MultibufferSelectionMode::All => {
16454                    editor.change_selections(
16455                        SelectionEffects::no_scroll(),
16456                        window,
16457                        cx,
16458                        |selections| {
16459                            selections.clear_disjoint();
16460                            selections.select_anchor_ranges(ranges);
16461                        },
16462                    );
16463                }
16464            }
16465            editor.register_buffers_with_language_servers(cx);
16466        });
16467
16468        let item = Box::new(editor);
16469        let item_id = item.item_id();
16470
16471        if split {
16472            workspace.split_item(SplitDirection::Right, item, window, cx);
16473        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16474            let (preview_item_id, preview_item_idx) =
16475                workspace.active_pane().read_with(cx, |pane, _| {
16476                    (pane.preview_item_id(), pane.preview_item_idx())
16477                });
16478
16479            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16480
16481            if let Some(preview_item_id) = preview_item_id {
16482                workspace.active_pane().update(cx, |pane, cx| {
16483                    pane.remove_item(preview_item_id, false, false, window, cx);
16484                });
16485            }
16486        } else {
16487            workspace.add_item_to_active_pane(item, None, true, window, cx);
16488        }
16489        workspace.active_pane().update(cx, |pane, cx| {
16490            pane.set_preview_item_id(Some(item_id), cx);
16491        });
16492    }
16493
16494    pub fn rename(
16495        &mut self,
16496        _: &Rename,
16497        window: &mut Window,
16498        cx: &mut Context<Self>,
16499    ) -> Option<Task<Result<()>>> {
16500        use language::ToOffset as _;
16501
16502        let provider = self.semantics_provider.clone()?;
16503        let selection = self.selections.newest_anchor().clone();
16504        let (cursor_buffer, cursor_buffer_position) = self
16505            .buffer
16506            .read(cx)
16507            .text_anchor_for_position(selection.head(), cx)?;
16508        let (tail_buffer, cursor_buffer_position_end) = self
16509            .buffer
16510            .read(cx)
16511            .text_anchor_for_position(selection.tail(), cx)?;
16512        if tail_buffer != cursor_buffer {
16513            return None;
16514        }
16515
16516        let snapshot = cursor_buffer.read(cx).snapshot();
16517        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16518        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16519        let prepare_rename = provider
16520            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16521            .unwrap_or_else(|| Task::ready(Ok(None)));
16522        drop(snapshot);
16523
16524        Some(cx.spawn_in(window, async move |this, cx| {
16525            let rename_range = if let Some(range) = prepare_rename.await? {
16526                Some(range)
16527            } else {
16528                this.update(cx, |this, cx| {
16529                    let buffer = this.buffer.read(cx).snapshot(cx);
16530                    let mut buffer_highlights = this
16531                        .document_highlights_for_position(selection.head(), &buffer)
16532                        .filter(|highlight| {
16533                            highlight.start.excerpt_id == selection.head().excerpt_id
16534                                && highlight.end.excerpt_id == selection.head().excerpt_id
16535                        });
16536                    buffer_highlights
16537                        .next()
16538                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16539                })?
16540            };
16541            if let Some(rename_range) = rename_range {
16542                this.update_in(cx, |this, window, cx| {
16543                    let snapshot = cursor_buffer.read(cx).snapshot();
16544                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16545                    let cursor_offset_in_rename_range =
16546                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16547                    let cursor_offset_in_rename_range_end =
16548                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16549
16550                    this.take_rename(false, window, cx);
16551                    let buffer = this.buffer.read(cx).read(cx);
16552                    let cursor_offset = selection.head().to_offset(&buffer);
16553                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16554                    let rename_end = rename_start + rename_buffer_range.len();
16555                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16556                    let mut old_highlight_id = None;
16557                    let old_name: Arc<str> = buffer
16558                        .chunks(rename_start..rename_end, true)
16559                        .map(|chunk| {
16560                            if old_highlight_id.is_none() {
16561                                old_highlight_id = chunk.syntax_highlight_id;
16562                            }
16563                            chunk.text
16564                        })
16565                        .collect::<String>()
16566                        .into();
16567
16568                    drop(buffer);
16569
16570                    // Position the selection in the rename editor so that it matches the current selection.
16571                    this.show_local_selections = false;
16572                    let rename_editor = cx.new(|cx| {
16573                        let mut editor = Editor::single_line(window, cx);
16574                        editor.buffer.update(cx, |buffer, cx| {
16575                            buffer.edit([(0..0, old_name.clone())], None, cx)
16576                        });
16577                        let rename_selection_range = match cursor_offset_in_rename_range
16578                            .cmp(&cursor_offset_in_rename_range_end)
16579                        {
16580                            Ordering::Equal => {
16581                                editor.select_all(&SelectAll, window, cx);
16582                                return editor;
16583                            }
16584                            Ordering::Less => {
16585                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16586                            }
16587                            Ordering::Greater => {
16588                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16589                            }
16590                        };
16591                        if rename_selection_range.end > old_name.len() {
16592                            editor.select_all(&SelectAll, window, cx);
16593                        } else {
16594                            editor.change_selections(Default::default(), window, cx, |s| {
16595                                s.select_ranges([rename_selection_range]);
16596                            });
16597                        }
16598                        editor
16599                    });
16600                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16601                        if e == &EditorEvent::Focused {
16602                            cx.emit(EditorEvent::FocusedIn)
16603                        }
16604                    })
16605                    .detach();
16606
16607                    let write_highlights =
16608                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16609                    let read_highlights =
16610                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16611                    let ranges = write_highlights
16612                        .iter()
16613                        .flat_map(|(_, ranges)| ranges.iter())
16614                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16615                        .cloned()
16616                        .collect();
16617
16618                    this.highlight_text::<Rename>(
16619                        ranges,
16620                        HighlightStyle {
16621                            fade_out: Some(0.6),
16622                            ..Default::default()
16623                        },
16624                        cx,
16625                    );
16626                    let rename_focus_handle = rename_editor.focus_handle(cx);
16627                    window.focus(&rename_focus_handle);
16628                    let block_id = this.insert_blocks(
16629                        [BlockProperties {
16630                            style: BlockStyle::Flex,
16631                            placement: BlockPlacement::Below(range.start),
16632                            height: Some(1),
16633                            render: Arc::new({
16634                                let rename_editor = rename_editor.clone();
16635                                move |cx: &mut BlockContext| {
16636                                    let mut text_style = cx.editor_style.text.clone();
16637                                    if let Some(highlight_style) = old_highlight_id
16638                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16639                                    {
16640                                        text_style = text_style.highlight(highlight_style);
16641                                    }
16642                                    div()
16643                                        .block_mouse_except_scroll()
16644                                        .pl(cx.anchor_x)
16645                                        .child(EditorElement::new(
16646                                            &rename_editor,
16647                                            EditorStyle {
16648                                                background: cx.theme().system().transparent,
16649                                                local_player: cx.editor_style.local_player,
16650                                                text: text_style,
16651                                                scrollbar_width: cx.editor_style.scrollbar_width,
16652                                                syntax: cx.editor_style.syntax.clone(),
16653                                                status: cx.editor_style.status.clone(),
16654                                                inlay_hints_style: HighlightStyle {
16655                                                    font_weight: Some(FontWeight::BOLD),
16656                                                    ..make_inlay_hints_style(cx.app)
16657                                                },
16658                                                edit_prediction_styles: make_suggestion_styles(
16659                                                    cx.app,
16660                                                ),
16661                                                ..EditorStyle::default()
16662                                            },
16663                                        ))
16664                                        .into_any_element()
16665                                }
16666                            }),
16667                            priority: 0,
16668                        }],
16669                        Some(Autoscroll::fit()),
16670                        cx,
16671                    )[0];
16672                    this.pending_rename = Some(RenameState {
16673                        range,
16674                        old_name,
16675                        editor: rename_editor,
16676                        block_id,
16677                    });
16678                })?;
16679            }
16680
16681            Ok(())
16682        }))
16683    }
16684
16685    pub fn confirm_rename(
16686        &mut self,
16687        _: &ConfirmRename,
16688        window: &mut Window,
16689        cx: &mut Context<Self>,
16690    ) -> Option<Task<Result<()>>> {
16691        let rename = self.take_rename(false, window, cx)?;
16692        let workspace = self.workspace()?.downgrade();
16693        let (buffer, start) = self
16694            .buffer
16695            .read(cx)
16696            .text_anchor_for_position(rename.range.start, cx)?;
16697        let (end_buffer, _) = self
16698            .buffer
16699            .read(cx)
16700            .text_anchor_for_position(rename.range.end, cx)?;
16701        if buffer != end_buffer {
16702            return None;
16703        }
16704
16705        let old_name = rename.old_name;
16706        let new_name = rename.editor.read(cx).text(cx);
16707
16708        let rename = self.semantics_provider.as_ref()?.perform_rename(
16709            &buffer,
16710            start,
16711            new_name.clone(),
16712            cx,
16713        )?;
16714
16715        Some(cx.spawn_in(window, async move |editor, cx| {
16716            let project_transaction = rename.await?;
16717            Self::open_project_transaction(
16718                &editor,
16719                workspace,
16720                project_transaction,
16721                format!("Rename: {}{}", old_name, new_name),
16722                cx,
16723            )
16724            .await?;
16725
16726            editor.update(cx, |editor, cx| {
16727                editor.refresh_document_highlights(cx);
16728            })?;
16729            Ok(())
16730        }))
16731    }
16732
16733    fn take_rename(
16734        &mut self,
16735        moving_cursor: bool,
16736        window: &mut Window,
16737        cx: &mut Context<Self>,
16738    ) -> Option<RenameState> {
16739        let rename = self.pending_rename.take()?;
16740        if rename.editor.focus_handle(cx).is_focused(window) {
16741            window.focus(&self.focus_handle);
16742        }
16743
16744        self.remove_blocks(
16745            [rename.block_id].into_iter().collect(),
16746            Some(Autoscroll::fit()),
16747            cx,
16748        );
16749        self.clear_highlights::<Rename>(cx);
16750        self.show_local_selections = true;
16751
16752        if moving_cursor {
16753            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16754                editor.selections.newest::<usize>(cx).head()
16755            });
16756
16757            // Update the selection to match the position of the selection inside
16758            // the rename editor.
16759            let snapshot = self.buffer.read(cx).read(cx);
16760            let rename_range = rename.range.to_offset(&snapshot);
16761            let cursor_in_editor = snapshot
16762                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16763                .min(rename_range.end);
16764            drop(snapshot);
16765
16766            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16767                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16768            });
16769        } else {
16770            self.refresh_document_highlights(cx);
16771        }
16772
16773        Some(rename)
16774    }
16775
16776    pub fn pending_rename(&self) -> Option<&RenameState> {
16777        self.pending_rename.as_ref()
16778    }
16779
16780    fn format(
16781        &mut self,
16782        _: &Format,
16783        window: &mut Window,
16784        cx: &mut Context<Self>,
16785    ) -> Option<Task<Result<()>>> {
16786        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16787
16788        let project = match &self.project {
16789            Some(project) => project.clone(),
16790            None => return None,
16791        };
16792
16793        Some(self.perform_format(
16794            project,
16795            FormatTrigger::Manual,
16796            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16797            window,
16798            cx,
16799        ))
16800    }
16801
16802    fn format_selections(
16803        &mut self,
16804        _: &FormatSelections,
16805        window: &mut Window,
16806        cx: &mut Context<Self>,
16807    ) -> Option<Task<Result<()>>> {
16808        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16809
16810        let project = match &self.project {
16811            Some(project) => project.clone(),
16812            None => return None,
16813        };
16814
16815        let ranges = self
16816            .selections
16817            .all_adjusted(cx)
16818            .into_iter()
16819            .map(|selection| selection.range())
16820            .collect_vec();
16821
16822        Some(self.perform_format(
16823            project,
16824            FormatTrigger::Manual,
16825            FormatTarget::Ranges(ranges),
16826            window,
16827            cx,
16828        ))
16829    }
16830
16831    fn perform_format(
16832        &mut self,
16833        project: Entity<Project>,
16834        trigger: FormatTrigger,
16835        target: FormatTarget,
16836        window: &mut Window,
16837        cx: &mut Context<Self>,
16838    ) -> Task<Result<()>> {
16839        let buffer = self.buffer.clone();
16840        let (buffers, target) = match target {
16841            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16842            FormatTarget::Ranges(selection_ranges) => {
16843                let multi_buffer = buffer.read(cx);
16844                let snapshot = multi_buffer.read(cx);
16845                let mut buffers = HashSet::default();
16846                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16847                    BTreeMap::new();
16848                for selection_range in selection_ranges {
16849                    for (buffer, buffer_range, _) in
16850                        snapshot.range_to_buffer_ranges(selection_range)
16851                    {
16852                        let buffer_id = buffer.remote_id();
16853                        let start = buffer.anchor_before(buffer_range.start);
16854                        let end = buffer.anchor_after(buffer_range.end);
16855                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16856                        buffer_id_to_ranges
16857                            .entry(buffer_id)
16858                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16859                            .or_insert_with(|| vec![start..end]);
16860                    }
16861                }
16862                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16863            }
16864        };
16865
16866        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16867        let selections_prev = transaction_id_prev
16868            .and_then(|transaction_id_prev| {
16869                // default to selections as they were after the last edit, if we have them,
16870                // instead of how they are now.
16871                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16872                // will take you back to where you made the last edit, instead of staying where you scrolled
16873                self.selection_history
16874                    .transaction(transaction_id_prev)
16875                    .map(|t| t.0.clone())
16876            })
16877            .unwrap_or_else(|| self.selections.disjoint_anchors());
16878
16879        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16880        let format = project.update(cx, |project, cx| {
16881            project.format(buffers, target, true, trigger, cx)
16882        });
16883
16884        cx.spawn_in(window, async move |editor, cx| {
16885            let transaction = futures::select_biased! {
16886                transaction = format.log_err().fuse() => transaction,
16887                () = timeout => {
16888                    log::warn!("timed out waiting for formatting");
16889                    None
16890                }
16891            };
16892
16893            buffer
16894                .update(cx, |buffer, cx| {
16895                    if let Some(transaction) = transaction
16896                        && !buffer.is_singleton()
16897                    {
16898                        buffer.push_transaction(&transaction.0, cx);
16899                    }
16900                    cx.notify();
16901                })
16902                .ok();
16903
16904            if let Some(transaction_id_now) =
16905                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16906            {
16907                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16908                if has_new_transaction {
16909                    _ = editor.update(cx, |editor, _| {
16910                        editor
16911                            .selection_history
16912                            .insert_transaction(transaction_id_now, selections_prev);
16913                    });
16914                }
16915            }
16916
16917            Ok(())
16918        })
16919    }
16920
16921    fn organize_imports(
16922        &mut self,
16923        _: &OrganizeImports,
16924        window: &mut Window,
16925        cx: &mut Context<Self>,
16926    ) -> Option<Task<Result<()>>> {
16927        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16928        let project = match &self.project {
16929            Some(project) => project.clone(),
16930            None => return None,
16931        };
16932        Some(self.perform_code_action_kind(
16933            project,
16934            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16935            window,
16936            cx,
16937        ))
16938    }
16939
16940    fn perform_code_action_kind(
16941        &mut self,
16942        project: Entity<Project>,
16943        kind: CodeActionKind,
16944        window: &mut Window,
16945        cx: &mut Context<Self>,
16946    ) -> Task<Result<()>> {
16947        let buffer = self.buffer.clone();
16948        let buffers = buffer.read(cx).all_buffers();
16949        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16950        let apply_action = project.update(cx, |project, cx| {
16951            project.apply_code_action_kind(buffers, kind, true, cx)
16952        });
16953        cx.spawn_in(window, async move |_, cx| {
16954            let transaction = futures::select_biased! {
16955                () = timeout => {
16956                    log::warn!("timed out waiting for executing code action");
16957                    None
16958                }
16959                transaction = apply_action.log_err().fuse() => transaction,
16960            };
16961            buffer
16962                .update(cx, |buffer, cx| {
16963                    // check if we need this
16964                    if let Some(transaction) = transaction
16965                        && !buffer.is_singleton()
16966                    {
16967                        buffer.push_transaction(&transaction.0, cx);
16968                    }
16969                    cx.notify();
16970                })
16971                .ok();
16972            Ok(())
16973        })
16974    }
16975
16976    pub fn restart_language_server(
16977        &mut self,
16978        _: &RestartLanguageServer,
16979        _: &mut Window,
16980        cx: &mut Context<Self>,
16981    ) {
16982        if let Some(project) = self.project.clone() {
16983            self.buffer.update(cx, |multi_buffer, cx| {
16984                project.update(cx, |project, cx| {
16985                    project.restart_language_servers_for_buffers(
16986                        multi_buffer.all_buffers().into_iter().collect(),
16987                        HashSet::default(),
16988                        cx,
16989                    );
16990                });
16991            })
16992        }
16993    }
16994
16995    pub fn stop_language_server(
16996        &mut self,
16997        _: &StopLanguageServer,
16998        _: &mut Window,
16999        cx: &mut Context<Self>,
17000    ) {
17001        if let Some(project) = self.project.clone() {
17002            self.buffer.update(cx, |multi_buffer, cx| {
17003                project.update(cx, |project, cx| {
17004                    project.stop_language_servers_for_buffers(
17005                        multi_buffer.all_buffers().into_iter().collect(),
17006                        HashSet::default(),
17007                        cx,
17008                    );
17009                    cx.emit(project::Event::RefreshInlayHints);
17010                });
17011            });
17012        }
17013    }
17014
17015    fn cancel_language_server_work(
17016        workspace: &mut Workspace,
17017        _: &actions::CancelLanguageServerWork,
17018        _: &mut Window,
17019        cx: &mut Context<Workspace>,
17020    ) {
17021        let project = workspace.project();
17022        let buffers = workspace
17023            .active_item(cx)
17024            .and_then(|item| item.act_as::<Editor>(cx))
17025            .map_or(HashSet::default(), |editor| {
17026                editor.read(cx).buffer.read(cx).all_buffers()
17027            });
17028        project.update(cx, |project, cx| {
17029            project.cancel_language_server_work_for_buffers(buffers, cx);
17030        });
17031    }
17032
17033    fn show_character_palette(
17034        &mut self,
17035        _: &ShowCharacterPalette,
17036        window: &mut Window,
17037        _: &mut Context<Self>,
17038    ) {
17039        window.show_character_palette();
17040    }
17041
17042    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17043        if !self.diagnostics_enabled() {
17044            return;
17045        }
17046
17047        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17048            let buffer = self.buffer.read(cx).snapshot(cx);
17049            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17050            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17051            let is_valid = buffer
17052                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17053                .any(|entry| {
17054                    entry.diagnostic.is_primary
17055                        && !entry.range.is_empty()
17056                        && entry.range.start == primary_range_start
17057                        && entry.diagnostic.message == active_diagnostics.active_message
17058                });
17059
17060            if !is_valid {
17061                self.dismiss_diagnostics(cx);
17062            }
17063        }
17064    }
17065
17066    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17067        match &self.active_diagnostics {
17068            ActiveDiagnostic::Group(group) => Some(group),
17069            _ => None,
17070        }
17071    }
17072
17073    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17074        if !self.diagnostics_enabled() {
17075            return;
17076        }
17077        self.dismiss_diagnostics(cx);
17078        self.active_diagnostics = ActiveDiagnostic::All;
17079    }
17080
17081    fn activate_diagnostics(
17082        &mut self,
17083        buffer_id: BufferId,
17084        diagnostic: DiagnosticEntry<usize>,
17085        window: &mut Window,
17086        cx: &mut Context<Self>,
17087    ) {
17088        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17089            return;
17090        }
17091        self.dismiss_diagnostics(cx);
17092        let snapshot = self.snapshot(window, cx);
17093        let buffer = self.buffer.read(cx).snapshot(cx);
17094        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17095            return;
17096        };
17097
17098        let diagnostic_group = buffer
17099            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17100            .collect::<Vec<_>>();
17101
17102        let blocks =
17103            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17104
17105        let blocks = self.display_map.update(cx, |display_map, cx| {
17106            display_map.insert_blocks(blocks, cx).into_iter().collect()
17107        });
17108        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17109            active_range: buffer.anchor_before(diagnostic.range.start)
17110                ..buffer.anchor_after(diagnostic.range.end),
17111            active_message: diagnostic.diagnostic.message.clone(),
17112            group_id: diagnostic.diagnostic.group_id,
17113            blocks,
17114        });
17115        cx.notify();
17116    }
17117
17118    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17119        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17120            return;
17121        };
17122
17123        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17124        if let ActiveDiagnostic::Group(group) = prev {
17125            self.display_map.update(cx, |display_map, cx| {
17126                display_map.remove_blocks(group.blocks, cx);
17127            });
17128            cx.notify();
17129        }
17130    }
17131
17132    /// Disable inline diagnostics rendering for this editor.
17133    pub fn disable_inline_diagnostics(&mut self) {
17134        self.inline_diagnostics_enabled = false;
17135        self.inline_diagnostics_update = Task::ready(());
17136        self.inline_diagnostics.clear();
17137    }
17138
17139    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17140        self.diagnostics_enabled = false;
17141        self.dismiss_diagnostics(cx);
17142        self.inline_diagnostics_update = Task::ready(());
17143        self.inline_diagnostics.clear();
17144    }
17145
17146    pub fn disable_word_completions(&mut self) {
17147        self.word_completions_enabled = false;
17148    }
17149
17150    pub fn diagnostics_enabled(&self) -> bool {
17151        self.diagnostics_enabled && self.mode.is_full()
17152    }
17153
17154    pub fn inline_diagnostics_enabled(&self) -> bool {
17155        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17156    }
17157
17158    pub fn show_inline_diagnostics(&self) -> bool {
17159        self.show_inline_diagnostics
17160    }
17161
17162    pub fn toggle_inline_diagnostics(
17163        &mut self,
17164        _: &ToggleInlineDiagnostics,
17165        window: &mut Window,
17166        cx: &mut Context<Editor>,
17167    ) {
17168        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17169        self.refresh_inline_diagnostics(false, window, cx);
17170    }
17171
17172    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17173        self.diagnostics_max_severity = severity;
17174        self.display_map.update(cx, |display_map, _| {
17175            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17176        });
17177    }
17178
17179    pub fn toggle_diagnostics(
17180        &mut self,
17181        _: &ToggleDiagnostics,
17182        window: &mut Window,
17183        cx: &mut Context<Editor>,
17184    ) {
17185        if !self.diagnostics_enabled() {
17186            return;
17187        }
17188
17189        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17190            EditorSettings::get_global(cx)
17191                .diagnostics_max_severity
17192                .filter(|severity| severity != &DiagnosticSeverity::Off)
17193                .unwrap_or(DiagnosticSeverity::Hint)
17194        } else {
17195            DiagnosticSeverity::Off
17196        };
17197        self.set_max_diagnostics_severity(new_severity, cx);
17198        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17199            self.active_diagnostics = ActiveDiagnostic::None;
17200            self.inline_diagnostics_update = Task::ready(());
17201            self.inline_diagnostics.clear();
17202        } else {
17203            self.refresh_inline_diagnostics(false, window, cx);
17204        }
17205
17206        cx.notify();
17207    }
17208
17209    pub fn toggle_minimap(
17210        &mut self,
17211        _: &ToggleMinimap,
17212        window: &mut Window,
17213        cx: &mut Context<Editor>,
17214    ) {
17215        if self.supports_minimap(cx) {
17216            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17217        }
17218    }
17219
17220    fn refresh_inline_diagnostics(
17221        &mut self,
17222        debounce: bool,
17223        window: &mut Window,
17224        cx: &mut Context<Self>,
17225    ) {
17226        let max_severity = ProjectSettings::get_global(cx)
17227            .diagnostics
17228            .inline
17229            .max_severity
17230            .unwrap_or(self.diagnostics_max_severity);
17231
17232        if !self.inline_diagnostics_enabled()
17233            || !self.show_inline_diagnostics
17234            || max_severity == DiagnosticSeverity::Off
17235        {
17236            self.inline_diagnostics_update = Task::ready(());
17237            self.inline_diagnostics.clear();
17238            return;
17239        }
17240
17241        let debounce_ms = ProjectSettings::get_global(cx)
17242            .diagnostics
17243            .inline
17244            .update_debounce_ms;
17245        let debounce = if debounce && debounce_ms > 0 {
17246            Some(Duration::from_millis(debounce_ms))
17247        } else {
17248            None
17249        };
17250        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17251            if let Some(debounce) = debounce {
17252                cx.background_executor().timer(debounce).await;
17253            }
17254            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17255                editor
17256                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17257                    .ok()
17258            }) else {
17259                return;
17260            };
17261
17262            let new_inline_diagnostics = cx
17263                .background_spawn(async move {
17264                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17265                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17266                        let message = diagnostic_entry
17267                            .diagnostic
17268                            .message
17269                            .split_once('\n')
17270                            .map(|(line, _)| line)
17271                            .map(SharedString::new)
17272                            .unwrap_or_else(|| {
17273                                SharedString::from(diagnostic_entry.diagnostic.message)
17274                            });
17275                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17276                        let (Ok(i) | Err(i)) = inline_diagnostics
17277                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17278                        inline_diagnostics.insert(
17279                            i,
17280                            (
17281                                start_anchor,
17282                                InlineDiagnostic {
17283                                    message,
17284                                    group_id: diagnostic_entry.diagnostic.group_id,
17285                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17286                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17287                                    severity: diagnostic_entry.diagnostic.severity,
17288                                },
17289                            ),
17290                        );
17291                    }
17292                    inline_diagnostics
17293                })
17294                .await;
17295
17296            editor
17297                .update(cx, |editor, cx| {
17298                    editor.inline_diagnostics = new_inline_diagnostics;
17299                    cx.notify();
17300                })
17301                .ok();
17302        });
17303    }
17304
17305    fn pull_diagnostics(
17306        &mut self,
17307        buffer_id: Option<BufferId>,
17308        window: &Window,
17309        cx: &mut Context<Self>,
17310    ) -> Option<()> {
17311        if !self.mode().is_full() {
17312            return None;
17313        }
17314        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17315            .diagnostics
17316            .lsp_pull_diagnostics;
17317        if !pull_diagnostics_settings.enabled {
17318            return None;
17319        }
17320        let project = self.project()?.downgrade();
17321        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17322        let mut buffers = self.buffer.read(cx).all_buffers();
17323        if let Some(buffer_id) = buffer_id {
17324            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17325        }
17326
17327        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17328            cx.background_executor().timer(debounce).await;
17329
17330            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17331                buffers
17332                    .into_iter()
17333                    .filter_map(|buffer| {
17334                        project
17335                            .update(cx, |project, cx| {
17336                                project.lsp_store().update(cx, |lsp_store, cx| {
17337                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17338                                })
17339                            })
17340                            .ok()
17341                    })
17342                    .collect::<FuturesUnordered<_>>()
17343            }) else {
17344                return;
17345            };
17346
17347            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17348                match pull_task {
17349                    Ok(()) => {
17350                        if editor
17351                            .update_in(cx, |editor, window, cx| {
17352                                editor.update_diagnostics_state(window, cx);
17353                            })
17354                            .is_err()
17355                        {
17356                            return;
17357                        }
17358                    }
17359                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17360                }
17361            }
17362        });
17363
17364        Some(())
17365    }
17366
17367    pub fn set_selections_from_remote(
17368        &mut self,
17369        selections: Vec<Selection<Anchor>>,
17370        pending_selection: Option<Selection<Anchor>>,
17371        window: &mut Window,
17372        cx: &mut Context<Self>,
17373    ) {
17374        let old_cursor_position = self.selections.newest_anchor().head();
17375        self.selections.change_with(cx, |s| {
17376            s.select_anchors(selections);
17377            if let Some(pending_selection) = pending_selection {
17378                s.set_pending(pending_selection, SelectMode::Character);
17379            } else {
17380                s.clear_pending();
17381            }
17382        });
17383        self.selections_did_change(
17384            false,
17385            &old_cursor_position,
17386            SelectionEffects::default(),
17387            window,
17388            cx,
17389        );
17390    }
17391
17392    pub fn transact(
17393        &mut self,
17394        window: &mut Window,
17395        cx: &mut Context<Self>,
17396        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17397    ) -> Option<TransactionId> {
17398        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17399            this.start_transaction_at(Instant::now(), window, cx);
17400            update(this, window, cx);
17401            this.end_transaction_at(Instant::now(), cx)
17402        })
17403    }
17404
17405    pub fn start_transaction_at(
17406        &mut self,
17407        now: Instant,
17408        window: &mut Window,
17409        cx: &mut Context<Self>,
17410    ) -> Option<TransactionId> {
17411        self.end_selection(window, cx);
17412        if let Some(tx_id) = self
17413            .buffer
17414            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17415        {
17416            self.selection_history
17417                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17418            cx.emit(EditorEvent::TransactionBegun {
17419                transaction_id: tx_id,
17420            });
17421            Some(tx_id)
17422        } else {
17423            None
17424        }
17425    }
17426
17427    pub fn end_transaction_at(
17428        &mut self,
17429        now: Instant,
17430        cx: &mut Context<Self>,
17431    ) -> Option<TransactionId> {
17432        if let Some(transaction_id) = self
17433            .buffer
17434            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17435        {
17436            if let Some((_, end_selections)) =
17437                self.selection_history.transaction_mut(transaction_id)
17438            {
17439                *end_selections = Some(self.selections.disjoint_anchors());
17440            } else {
17441                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17442            }
17443
17444            cx.emit(EditorEvent::Edited { transaction_id });
17445            Some(transaction_id)
17446        } else {
17447            None
17448        }
17449    }
17450
17451    pub fn modify_transaction_selection_history(
17452        &mut self,
17453        transaction_id: TransactionId,
17454        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17455    ) -> bool {
17456        self.selection_history
17457            .transaction_mut(transaction_id)
17458            .map(modify)
17459            .is_some()
17460    }
17461
17462    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17463        if self.selection_mark_mode {
17464            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17465                s.move_with(|_, sel| {
17466                    sel.collapse_to(sel.head(), SelectionGoal::None);
17467                });
17468            })
17469        }
17470        self.selection_mark_mode = true;
17471        cx.notify();
17472    }
17473
17474    pub fn swap_selection_ends(
17475        &mut self,
17476        _: &actions::SwapSelectionEnds,
17477        window: &mut Window,
17478        cx: &mut Context<Self>,
17479    ) {
17480        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17481            s.move_with(|_, sel| {
17482                if sel.start != sel.end {
17483                    sel.reversed = !sel.reversed
17484                }
17485            });
17486        });
17487        self.request_autoscroll(Autoscroll::newest(), cx);
17488        cx.notify();
17489    }
17490
17491    pub fn toggle_focus(
17492        workspace: &mut Workspace,
17493        _: &actions::ToggleFocus,
17494        window: &mut Window,
17495        cx: &mut Context<Workspace>,
17496    ) {
17497        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17498            return;
17499        };
17500        workspace.activate_item(&item, true, true, window, cx);
17501    }
17502
17503    pub fn toggle_fold(
17504        &mut self,
17505        _: &actions::ToggleFold,
17506        window: &mut Window,
17507        cx: &mut Context<Self>,
17508    ) {
17509        if self.is_singleton(cx) {
17510            let selection = self.selections.newest::<Point>(cx);
17511
17512            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17513            let range = if selection.is_empty() {
17514                let point = selection.head().to_display_point(&display_map);
17515                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17516                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17517                    .to_point(&display_map);
17518                start..end
17519            } else {
17520                selection.range()
17521            };
17522            if display_map.folds_in_range(range).next().is_some() {
17523                self.unfold_lines(&Default::default(), window, cx)
17524            } else {
17525                self.fold(&Default::default(), window, cx)
17526            }
17527        } else {
17528            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17529            let buffer_ids: HashSet<_> = self
17530                .selections
17531                .disjoint_anchor_ranges()
17532                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17533                .collect();
17534
17535            let should_unfold = buffer_ids
17536                .iter()
17537                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17538
17539            for buffer_id in buffer_ids {
17540                if should_unfold {
17541                    self.unfold_buffer(buffer_id, cx);
17542                } else {
17543                    self.fold_buffer(buffer_id, cx);
17544                }
17545            }
17546        }
17547    }
17548
17549    pub fn toggle_fold_recursive(
17550        &mut self,
17551        _: &actions::ToggleFoldRecursive,
17552        window: &mut Window,
17553        cx: &mut Context<Self>,
17554    ) {
17555        let selection = self.selections.newest::<Point>(cx);
17556
17557        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17558        let range = if selection.is_empty() {
17559            let point = selection.head().to_display_point(&display_map);
17560            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17561            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17562                .to_point(&display_map);
17563            start..end
17564        } else {
17565            selection.range()
17566        };
17567        if display_map.folds_in_range(range).next().is_some() {
17568            self.unfold_recursive(&Default::default(), window, cx)
17569        } else {
17570            self.fold_recursive(&Default::default(), window, cx)
17571        }
17572    }
17573
17574    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17575        if self.is_singleton(cx) {
17576            let mut to_fold = Vec::new();
17577            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17578            let selections = self.selections.all_adjusted(cx);
17579
17580            for selection in selections {
17581                let range = selection.range().sorted();
17582                let buffer_start_row = range.start.row;
17583
17584                if range.start.row != range.end.row {
17585                    let mut found = false;
17586                    let mut row = range.start.row;
17587                    while row <= range.end.row {
17588                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17589                        {
17590                            found = true;
17591                            row = crease.range().end.row + 1;
17592                            to_fold.push(crease);
17593                        } else {
17594                            row += 1
17595                        }
17596                    }
17597                    if found {
17598                        continue;
17599                    }
17600                }
17601
17602                for row in (0..=range.start.row).rev() {
17603                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17604                        && crease.range().end.row >= buffer_start_row
17605                    {
17606                        to_fold.push(crease);
17607                        if row <= range.start.row {
17608                            break;
17609                        }
17610                    }
17611                }
17612            }
17613
17614            self.fold_creases(to_fold, true, window, cx);
17615        } else {
17616            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17617            let buffer_ids = self
17618                .selections
17619                .disjoint_anchor_ranges()
17620                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17621                .collect::<HashSet<_>>();
17622            for buffer_id in buffer_ids {
17623                self.fold_buffer(buffer_id, cx);
17624            }
17625        }
17626    }
17627
17628    pub fn toggle_fold_all(
17629        &mut self,
17630        _: &actions::ToggleFoldAll,
17631        window: &mut Window,
17632        cx: &mut Context<Self>,
17633    ) {
17634        if self.buffer.read(cx).is_singleton() {
17635            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17636            let has_folds = display_map
17637                .folds_in_range(0..display_map.buffer_snapshot.len())
17638                .next()
17639                .is_some();
17640
17641            if has_folds {
17642                self.unfold_all(&actions::UnfoldAll, window, cx);
17643            } else {
17644                self.fold_all(&actions::FoldAll, window, cx);
17645            }
17646        } else {
17647            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17648            let should_unfold = buffer_ids
17649                .iter()
17650                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17651
17652            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17653                editor
17654                    .update_in(cx, |editor, _, cx| {
17655                        for buffer_id in buffer_ids {
17656                            if should_unfold {
17657                                editor.unfold_buffer(buffer_id, cx);
17658                            } else {
17659                                editor.fold_buffer(buffer_id, cx);
17660                            }
17661                        }
17662                    })
17663                    .ok();
17664            });
17665        }
17666    }
17667
17668    fn fold_at_level(
17669        &mut self,
17670        fold_at: &FoldAtLevel,
17671        window: &mut Window,
17672        cx: &mut Context<Self>,
17673    ) {
17674        if !self.buffer.read(cx).is_singleton() {
17675            return;
17676        }
17677
17678        let fold_at_level = fold_at.0;
17679        let snapshot = self.buffer.read(cx).snapshot(cx);
17680        let mut to_fold = Vec::new();
17681        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17682
17683        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17684            while start_row < end_row {
17685                match self
17686                    .snapshot(window, cx)
17687                    .crease_for_buffer_row(MultiBufferRow(start_row))
17688                {
17689                    Some(crease) => {
17690                        let nested_start_row = crease.range().start.row + 1;
17691                        let nested_end_row = crease.range().end.row;
17692
17693                        if current_level < fold_at_level {
17694                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17695                        } else if current_level == fold_at_level {
17696                            to_fold.push(crease);
17697                        }
17698
17699                        start_row = nested_end_row + 1;
17700                    }
17701                    None => start_row += 1,
17702                }
17703            }
17704        }
17705
17706        self.fold_creases(to_fold, true, window, cx);
17707    }
17708
17709    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17710        if self.buffer.read(cx).is_singleton() {
17711            let mut fold_ranges = Vec::new();
17712            let snapshot = self.buffer.read(cx).snapshot(cx);
17713
17714            for row in 0..snapshot.max_row().0 {
17715                if let Some(foldable_range) = self
17716                    .snapshot(window, cx)
17717                    .crease_for_buffer_row(MultiBufferRow(row))
17718                {
17719                    fold_ranges.push(foldable_range);
17720                }
17721            }
17722
17723            self.fold_creases(fold_ranges, true, window, cx);
17724        } else {
17725            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17726                editor
17727                    .update_in(cx, |editor, _, cx| {
17728                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17729                            editor.fold_buffer(buffer_id, cx);
17730                        }
17731                    })
17732                    .ok();
17733            });
17734        }
17735    }
17736
17737    pub fn fold_function_bodies(
17738        &mut self,
17739        _: &actions::FoldFunctionBodies,
17740        window: &mut Window,
17741        cx: &mut Context<Self>,
17742    ) {
17743        let snapshot = self.buffer.read(cx).snapshot(cx);
17744
17745        let ranges = snapshot
17746            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17747            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17748            .collect::<Vec<_>>();
17749
17750        let creases = ranges
17751            .into_iter()
17752            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17753            .collect();
17754
17755        self.fold_creases(creases, true, window, cx);
17756    }
17757
17758    pub fn fold_recursive(
17759        &mut self,
17760        _: &actions::FoldRecursive,
17761        window: &mut Window,
17762        cx: &mut Context<Self>,
17763    ) {
17764        let mut to_fold = Vec::new();
17765        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17766        let selections = self.selections.all_adjusted(cx);
17767
17768        for selection in selections {
17769            let range = selection.range().sorted();
17770            let buffer_start_row = range.start.row;
17771
17772            if range.start.row != range.end.row {
17773                let mut found = false;
17774                for row in range.start.row..=range.end.row {
17775                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17776                        found = true;
17777                        to_fold.push(crease);
17778                    }
17779                }
17780                if found {
17781                    continue;
17782                }
17783            }
17784
17785            for row in (0..=range.start.row).rev() {
17786                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17787                    if crease.range().end.row >= buffer_start_row {
17788                        to_fold.push(crease);
17789                    } else {
17790                        break;
17791                    }
17792                }
17793            }
17794        }
17795
17796        self.fold_creases(to_fold, true, window, cx);
17797    }
17798
17799    pub fn fold_at(
17800        &mut self,
17801        buffer_row: MultiBufferRow,
17802        window: &mut Window,
17803        cx: &mut Context<Self>,
17804    ) {
17805        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17806
17807        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17808            let autoscroll = self
17809                .selections
17810                .all::<Point>(cx)
17811                .iter()
17812                .any(|selection| crease.range().overlaps(&selection.range()));
17813
17814            self.fold_creases(vec![crease], autoscroll, window, cx);
17815        }
17816    }
17817
17818    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17819        if self.is_singleton(cx) {
17820            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17821            let buffer = &display_map.buffer_snapshot;
17822            let selections = self.selections.all::<Point>(cx);
17823            let ranges = selections
17824                .iter()
17825                .map(|s| {
17826                    let range = s.display_range(&display_map).sorted();
17827                    let mut start = range.start.to_point(&display_map);
17828                    let mut end = range.end.to_point(&display_map);
17829                    start.column = 0;
17830                    end.column = buffer.line_len(MultiBufferRow(end.row));
17831                    start..end
17832                })
17833                .collect::<Vec<_>>();
17834
17835            self.unfold_ranges(&ranges, true, true, cx);
17836        } else {
17837            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17838            let buffer_ids = self
17839                .selections
17840                .disjoint_anchor_ranges()
17841                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17842                .collect::<HashSet<_>>();
17843            for buffer_id in buffer_ids {
17844                self.unfold_buffer(buffer_id, cx);
17845            }
17846        }
17847    }
17848
17849    pub fn unfold_recursive(
17850        &mut self,
17851        _: &UnfoldRecursive,
17852        _window: &mut Window,
17853        cx: &mut Context<Self>,
17854    ) {
17855        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17856        let selections = self.selections.all::<Point>(cx);
17857        let ranges = selections
17858            .iter()
17859            .map(|s| {
17860                let mut range = s.display_range(&display_map).sorted();
17861                *range.start.column_mut() = 0;
17862                *range.end.column_mut() = display_map.line_len(range.end.row());
17863                let start = range.start.to_point(&display_map);
17864                let end = range.end.to_point(&display_map);
17865                start..end
17866            })
17867            .collect::<Vec<_>>();
17868
17869        self.unfold_ranges(&ranges, true, true, cx);
17870    }
17871
17872    pub fn unfold_at(
17873        &mut self,
17874        buffer_row: MultiBufferRow,
17875        _window: &mut Window,
17876        cx: &mut Context<Self>,
17877    ) {
17878        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17879
17880        let intersection_range = Point::new(buffer_row.0, 0)
17881            ..Point::new(
17882                buffer_row.0,
17883                display_map.buffer_snapshot.line_len(buffer_row),
17884            );
17885
17886        let autoscroll = self
17887            .selections
17888            .all::<Point>(cx)
17889            .iter()
17890            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17891
17892        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17893    }
17894
17895    pub fn unfold_all(
17896        &mut self,
17897        _: &actions::UnfoldAll,
17898        _window: &mut Window,
17899        cx: &mut Context<Self>,
17900    ) {
17901        if self.buffer.read(cx).is_singleton() {
17902            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17903            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17904        } else {
17905            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17906                editor
17907                    .update(cx, |editor, cx| {
17908                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17909                            editor.unfold_buffer(buffer_id, cx);
17910                        }
17911                    })
17912                    .ok();
17913            });
17914        }
17915    }
17916
17917    pub fn fold_selected_ranges(
17918        &mut self,
17919        _: &FoldSelectedRanges,
17920        window: &mut Window,
17921        cx: &mut Context<Self>,
17922    ) {
17923        let selections = self.selections.all_adjusted(cx);
17924        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17925        let ranges = selections
17926            .into_iter()
17927            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17928            .collect::<Vec<_>>();
17929        self.fold_creases(ranges, true, window, cx);
17930    }
17931
17932    pub fn fold_ranges<T: ToOffset + Clone>(
17933        &mut self,
17934        ranges: Vec<Range<T>>,
17935        auto_scroll: bool,
17936        window: &mut Window,
17937        cx: &mut Context<Self>,
17938    ) {
17939        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17940        let ranges = ranges
17941            .into_iter()
17942            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17943            .collect::<Vec<_>>();
17944        self.fold_creases(ranges, auto_scroll, window, cx);
17945    }
17946
17947    pub fn fold_creases<T: ToOffset + Clone>(
17948        &mut self,
17949        creases: Vec<Crease<T>>,
17950        auto_scroll: bool,
17951        _window: &mut Window,
17952        cx: &mut Context<Self>,
17953    ) {
17954        if creases.is_empty() {
17955            return;
17956        }
17957
17958        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17959
17960        if auto_scroll {
17961            self.request_autoscroll(Autoscroll::fit(), cx);
17962        }
17963
17964        cx.notify();
17965
17966        self.scrollbar_marker_state.dirty = true;
17967        self.folds_did_change(cx);
17968    }
17969
17970    /// Removes any folds whose ranges intersect any of the given ranges.
17971    pub fn unfold_ranges<T: ToOffset + Clone>(
17972        &mut self,
17973        ranges: &[Range<T>],
17974        inclusive: bool,
17975        auto_scroll: bool,
17976        cx: &mut Context<Self>,
17977    ) {
17978        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17979            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17980        });
17981        self.folds_did_change(cx);
17982    }
17983
17984    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17985        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17986            return;
17987        }
17988        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17989        self.display_map.update(cx, |display_map, cx| {
17990            display_map.fold_buffers([buffer_id], cx)
17991        });
17992        cx.emit(EditorEvent::BufferFoldToggled {
17993            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17994            folded: true,
17995        });
17996        cx.notify();
17997    }
17998
17999    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18000        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18001            return;
18002        }
18003        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18004        self.display_map.update(cx, |display_map, cx| {
18005            display_map.unfold_buffers([buffer_id], cx);
18006        });
18007        cx.emit(EditorEvent::BufferFoldToggled {
18008            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18009            folded: false,
18010        });
18011        cx.notify();
18012    }
18013
18014    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18015        self.display_map.read(cx).is_buffer_folded(buffer)
18016    }
18017
18018    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18019        self.display_map.read(cx).folded_buffers()
18020    }
18021
18022    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18023        self.display_map.update(cx, |display_map, cx| {
18024            display_map.disable_header_for_buffer(buffer_id, cx);
18025        });
18026        cx.notify();
18027    }
18028
18029    /// Removes any folds with the given ranges.
18030    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18031        &mut self,
18032        ranges: &[Range<T>],
18033        type_id: TypeId,
18034        auto_scroll: bool,
18035        cx: &mut Context<Self>,
18036    ) {
18037        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18038            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18039        });
18040        self.folds_did_change(cx);
18041    }
18042
18043    fn remove_folds_with<T: ToOffset + Clone>(
18044        &mut self,
18045        ranges: &[Range<T>],
18046        auto_scroll: bool,
18047        cx: &mut Context<Self>,
18048        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18049    ) {
18050        if ranges.is_empty() {
18051            return;
18052        }
18053
18054        let mut buffers_affected = HashSet::default();
18055        let multi_buffer = self.buffer().read(cx);
18056        for range in ranges {
18057            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18058                buffers_affected.insert(buffer.read(cx).remote_id());
18059            };
18060        }
18061
18062        self.display_map.update(cx, update);
18063
18064        if auto_scroll {
18065            self.request_autoscroll(Autoscroll::fit(), cx);
18066        }
18067
18068        cx.notify();
18069        self.scrollbar_marker_state.dirty = true;
18070        self.active_indent_guides_state.dirty = true;
18071    }
18072
18073    pub fn update_renderer_widths(
18074        &mut self,
18075        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18076        cx: &mut Context<Self>,
18077    ) -> bool {
18078        self.display_map
18079            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18080    }
18081
18082    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18083        self.display_map.read(cx).fold_placeholder.clone()
18084    }
18085
18086    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18087        self.buffer.update(cx, |buffer, cx| {
18088            buffer.set_all_diff_hunks_expanded(cx);
18089        });
18090    }
18091
18092    pub fn expand_all_diff_hunks(
18093        &mut self,
18094        _: &ExpandAllDiffHunks,
18095        _window: &mut Window,
18096        cx: &mut Context<Self>,
18097    ) {
18098        self.buffer.update(cx, |buffer, cx| {
18099            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18100        });
18101    }
18102
18103    pub fn toggle_selected_diff_hunks(
18104        &mut self,
18105        _: &ToggleSelectedDiffHunks,
18106        _window: &mut Window,
18107        cx: &mut Context<Self>,
18108    ) {
18109        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18110        self.toggle_diff_hunks_in_ranges(ranges, cx);
18111    }
18112
18113    pub fn diff_hunks_in_ranges<'a>(
18114        &'a self,
18115        ranges: &'a [Range<Anchor>],
18116        buffer: &'a MultiBufferSnapshot,
18117    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18118        ranges.iter().flat_map(move |range| {
18119            let end_excerpt_id = range.end.excerpt_id;
18120            let range = range.to_point(buffer);
18121            let mut peek_end = range.end;
18122            if range.end.row < buffer.max_row().0 {
18123                peek_end = Point::new(range.end.row + 1, 0);
18124            }
18125            buffer
18126                .diff_hunks_in_range(range.start..peek_end)
18127                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18128        })
18129    }
18130
18131    pub fn has_stageable_diff_hunks_in_ranges(
18132        &self,
18133        ranges: &[Range<Anchor>],
18134        snapshot: &MultiBufferSnapshot,
18135    ) -> bool {
18136        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18137        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18138    }
18139
18140    pub fn toggle_staged_selected_diff_hunks(
18141        &mut self,
18142        _: &::git::ToggleStaged,
18143        _: &mut Window,
18144        cx: &mut Context<Self>,
18145    ) {
18146        let snapshot = self.buffer.read(cx).snapshot(cx);
18147        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18148        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18149        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18150    }
18151
18152    pub fn set_render_diff_hunk_controls(
18153        &mut self,
18154        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18155        cx: &mut Context<Self>,
18156    ) {
18157        self.render_diff_hunk_controls = render_diff_hunk_controls;
18158        cx.notify();
18159    }
18160
18161    pub fn stage_and_next(
18162        &mut self,
18163        _: &::git::StageAndNext,
18164        window: &mut Window,
18165        cx: &mut Context<Self>,
18166    ) {
18167        self.do_stage_or_unstage_and_next(true, window, cx);
18168    }
18169
18170    pub fn unstage_and_next(
18171        &mut self,
18172        _: &::git::UnstageAndNext,
18173        window: &mut Window,
18174        cx: &mut Context<Self>,
18175    ) {
18176        self.do_stage_or_unstage_and_next(false, window, cx);
18177    }
18178
18179    pub fn stage_or_unstage_diff_hunks(
18180        &mut self,
18181        stage: bool,
18182        ranges: Vec<Range<Anchor>>,
18183        cx: &mut Context<Self>,
18184    ) {
18185        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18186        cx.spawn(async move |this, cx| {
18187            task.await?;
18188            this.update(cx, |this, cx| {
18189                let snapshot = this.buffer.read(cx).snapshot(cx);
18190                let chunk_by = this
18191                    .diff_hunks_in_ranges(&ranges, &snapshot)
18192                    .chunk_by(|hunk| hunk.buffer_id);
18193                for (buffer_id, hunks) in &chunk_by {
18194                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18195                }
18196            })
18197        })
18198        .detach_and_log_err(cx);
18199    }
18200
18201    fn save_buffers_for_ranges_if_needed(
18202        &mut self,
18203        ranges: &[Range<Anchor>],
18204        cx: &mut Context<Editor>,
18205    ) -> Task<Result<()>> {
18206        let multibuffer = self.buffer.read(cx);
18207        let snapshot = multibuffer.read(cx);
18208        let buffer_ids: HashSet<_> = ranges
18209            .iter()
18210            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18211            .collect();
18212        drop(snapshot);
18213
18214        let mut buffers = HashSet::default();
18215        for buffer_id in buffer_ids {
18216            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18217                let buffer = buffer_entity.read(cx);
18218                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18219                {
18220                    buffers.insert(buffer_entity);
18221                }
18222            }
18223        }
18224
18225        if let Some(project) = &self.project {
18226            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18227        } else {
18228            Task::ready(Ok(()))
18229        }
18230    }
18231
18232    fn do_stage_or_unstage_and_next(
18233        &mut self,
18234        stage: bool,
18235        window: &mut Window,
18236        cx: &mut Context<Self>,
18237    ) {
18238        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18239
18240        if ranges.iter().any(|range| range.start != range.end) {
18241            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18242            return;
18243        }
18244
18245        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18246        let snapshot = self.snapshot(window, cx);
18247        let position = self.selections.newest::<Point>(cx).head();
18248        let mut row = snapshot
18249            .buffer_snapshot
18250            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18251            .find(|hunk| hunk.row_range.start.0 > position.row)
18252            .map(|hunk| hunk.row_range.start);
18253
18254        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18255        // Outside of the project diff editor, wrap around to the beginning.
18256        if !all_diff_hunks_expanded {
18257            row = row.or_else(|| {
18258                snapshot
18259                    .buffer_snapshot
18260                    .diff_hunks_in_range(Point::zero()..position)
18261                    .find(|hunk| hunk.row_range.end.0 < position.row)
18262                    .map(|hunk| hunk.row_range.start)
18263            });
18264        }
18265
18266        if let Some(row) = row {
18267            let destination = Point::new(row.0, 0);
18268            let autoscroll = Autoscroll::center();
18269
18270            self.unfold_ranges(&[destination..destination], false, false, cx);
18271            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18272                s.select_ranges([destination..destination]);
18273            });
18274        }
18275    }
18276
18277    fn do_stage_or_unstage(
18278        &self,
18279        stage: bool,
18280        buffer_id: BufferId,
18281        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18282        cx: &mut App,
18283    ) -> Option<()> {
18284        let project = self.project()?;
18285        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18286        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18287        let buffer_snapshot = buffer.read(cx).snapshot();
18288        let file_exists = buffer_snapshot
18289            .file()
18290            .is_some_and(|file| file.disk_state().exists());
18291        diff.update(cx, |diff, cx| {
18292            diff.stage_or_unstage_hunks(
18293                stage,
18294                &hunks
18295                    .map(|hunk| buffer_diff::DiffHunk {
18296                        buffer_range: hunk.buffer_range,
18297                        diff_base_byte_range: hunk.diff_base_byte_range,
18298                        secondary_status: hunk.secondary_status,
18299                        range: Point::zero()..Point::zero(), // unused
18300                    })
18301                    .collect::<Vec<_>>(),
18302                &buffer_snapshot,
18303                file_exists,
18304                cx,
18305            )
18306        });
18307        None
18308    }
18309
18310    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18311        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18312        self.buffer
18313            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18314    }
18315
18316    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18317        self.buffer.update(cx, |buffer, cx| {
18318            let ranges = vec![Anchor::min()..Anchor::max()];
18319            if !buffer.all_diff_hunks_expanded()
18320                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18321            {
18322                buffer.collapse_diff_hunks(ranges, cx);
18323                true
18324            } else {
18325                false
18326            }
18327        })
18328    }
18329
18330    fn toggle_diff_hunks_in_ranges(
18331        &mut self,
18332        ranges: Vec<Range<Anchor>>,
18333        cx: &mut Context<Editor>,
18334    ) {
18335        self.buffer.update(cx, |buffer, cx| {
18336            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18337            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18338        })
18339    }
18340
18341    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18342        self.buffer.update(cx, |buffer, cx| {
18343            let snapshot = buffer.snapshot(cx);
18344            let excerpt_id = range.end.excerpt_id;
18345            let point_range = range.to_point(&snapshot);
18346            let expand = !buffer.single_hunk_is_expanded(range, cx);
18347            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18348        })
18349    }
18350
18351    pub(crate) fn apply_all_diff_hunks(
18352        &mut self,
18353        _: &ApplyAllDiffHunks,
18354        window: &mut Window,
18355        cx: &mut Context<Self>,
18356    ) {
18357        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18358
18359        let buffers = self.buffer.read(cx).all_buffers();
18360        for branch_buffer in buffers {
18361            branch_buffer.update(cx, |branch_buffer, cx| {
18362                branch_buffer.merge_into_base(Vec::new(), cx);
18363            });
18364        }
18365
18366        if let Some(project) = self.project.clone() {
18367            self.save(
18368                SaveOptions {
18369                    format: true,
18370                    autosave: false,
18371                },
18372                project,
18373                window,
18374                cx,
18375            )
18376            .detach_and_log_err(cx);
18377        }
18378    }
18379
18380    pub(crate) fn apply_selected_diff_hunks(
18381        &mut self,
18382        _: &ApplyDiffHunk,
18383        window: &mut Window,
18384        cx: &mut Context<Self>,
18385    ) {
18386        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18387        let snapshot = self.snapshot(window, cx);
18388        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18389        let mut ranges_by_buffer = HashMap::default();
18390        self.transact(window, cx, |editor, _window, cx| {
18391            for hunk in hunks {
18392                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18393                    ranges_by_buffer
18394                        .entry(buffer.clone())
18395                        .or_insert_with(Vec::new)
18396                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18397                }
18398            }
18399
18400            for (buffer, ranges) in ranges_by_buffer {
18401                buffer.update(cx, |buffer, cx| {
18402                    buffer.merge_into_base(ranges, cx);
18403                });
18404            }
18405        });
18406
18407        if let Some(project) = self.project.clone() {
18408            self.save(
18409                SaveOptions {
18410                    format: true,
18411                    autosave: false,
18412                },
18413                project,
18414                window,
18415                cx,
18416            )
18417            .detach_and_log_err(cx);
18418        }
18419    }
18420
18421    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18422        if hovered != self.gutter_hovered {
18423            self.gutter_hovered = hovered;
18424            cx.notify();
18425        }
18426    }
18427
18428    pub fn insert_blocks(
18429        &mut self,
18430        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18431        autoscroll: Option<Autoscroll>,
18432        cx: &mut Context<Self>,
18433    ) -> Vec<CustomBlockId> {
18434        let blocks = self
18435            .display_map
18436            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18437        if let Some(autoscroll) = autoscroll {
18438            self.request_autoscroll(autoscroll, cx);
18439        }
18440        cx.notify();
18441        blocks
18442    }
18443
18444    pub fn resize_blocks(
18445        &mut self,
18446        heights: HashMap<CustomBlockId, u32>,
18447        autoscroll: Option<Autoscroll>,
18448        cx: &mut Context<Self>,
18449    ) {
18450        self.display_map
18451            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18452        if let Some(autoscroll) = autoscroll {
18453            self.request_autoscroll(autoscroll, cx);
18454        }
18455        cx.notify();
18456    }
18457
18458    pub fn replace_blocks(
18459        &mut self,
18460        renderers: HashMap<CustomBlockId, RenderBlock>,
18461        autoscroll: Option<Autoscroll>,
18462        cx: &mut Context<Self>,
18463    ) {
18464        self.display_map
18465            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18466        if let Some(autoscroll) = autoscroll {
18467            self.request_autoscroll(autoscroll, cx);
18468        }
18469        cx.notify();
18470    }
18471
18472    pub fn remove_blocks(
18473        &mut self,
18474        block_ids: HashSet<CustomBlockId>,
18475        autoscroll: Option<Autoscroll>,
18476        cx: &mut Context<Self>,
18477    ) {
18478        self.display_map.update(cx, |display_map, cx| {
18479            display_map.remove_blocks(block_ids, cx)
18480        });
18481        if let Some(autoscroll) = autoscroll {
18482            self.request_autoscroll(autoscroll, cx);
18483        }
18484        cx.notify();
18485    }
18486
18487    pub fn row_for_block(
18488        &self,
18489        block_id: CustomBlockId,
18490        cx: &mut Context<Self>,
18491    ) -> Option<DisplayRow> {
18492        self.display_map
18493            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18494    }
18495
18496    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18497        self.focused_block = Some(focused_block);
18498    }
18499
18500    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18501        self.focused_block.take()
18502    }
18503
18504    pub fn insert_creases(
18505        &mut self,
18506        creases: impl IntoIterator<Item = Crease<Anchor>>,
18507        cx: &mut Context<Self>,
18508    ) -> Vec<CreaseId> {
18509        self.display_map
18510            .update(cx, |map, cx| map.insert_creases(creases, cx))
18511    }
18512
18513    pub fn remove_creases(
18514        &mut self,
18515        ids: impl IntoIterator<Item = CreaseId>,
18516        cx: &mut Context<Self>,
18517    ) -> Vec<(CreaseId, Range<Anchor>)> {
18518        self.display_map
18519            .update(cx, |map, cx| map.remove_creases(ids, cx))
18520    }
18521
18522    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18523        self.display_map
18524            .update(cx, |map, cx| map.snapshot(cx))
18525            .longest_row()
18526    }
18527
18528    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18529        self.display_map
18530            .update(cx, |map, cx| map.snapshot(cx))
18531            .max_point()
18532    }
18533
18534    pub fn text(&self, cx: &App) -> String {
18535        self.buffer.read(cx).read(cx).text()
18536    }
18537
18538    pub fn is_empty(&self, cx: &App) -> bool {
18539        self.buffer.read(cx).read(cx).is_empty()
18540    }
18541
18542    pub fn text_option(&self, cx: &App) -> Option<String> {
18543        let text = self.text(cx);
18544        let text = text.trim();
18545
18546        if text.is_empty() {
18547            return None;
18548        }
18549
18550        Some(text.to_string())
18551    }
18552
18553    pub fn set_text(
18554        &mut self,
18555        text: impl Into<Arc<str>>,
18556        window: &mut Window,
18557        cx: &mut Context<Self>,
18558    ) {
18559        self.transact(window, cx, |this, _, cx| {
18560            this.buffer
18561                .read(cx)
18562                .as_singleton()
18563                .expect("you can only call set_text on editors for singleton buffers")
18564                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18565        });
18566    }
18567
18568    pub fn display_text(&self, cx: &mut App) -> String {
18569        self.display_map
18570            .update(cx, |map, cx| map.snapshot(cx))
18571            .text()
18572    }
18573
18574    fn create_minimap(
18575        &self,
18576        minimap_settings: MinimapSettings,
18577        window: &mut Window,
18578        cx: &mut Context<Self>,
18579    ) -> Option<Entity<Self>> {
18580        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18581            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18582    }
18583
18584    fn initialize_new_minimap(
18585        &self,
18586        minimap_settings: MinimapSettings,
18587        window: &mut Window,
18588        cx: &mut Context<Self>,
18589    ) -> Entity<Self> {
18590        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18591
18592        let mut minimap = Editor::new_internal(
18593            EditorMode::Minimap {
18594                parent: cx.weak_entity(),
18595            },
18596            self.buffer.clone(),
18597            None,
18598            Some(self.display_map.clone()),
18599            window,
18600            cx,
18601        );
18602        minimap.scroll_manager.clone_state(&self.scroll_manager);
18603        minimap.set_text_style_refinement(TextStyleRefinement {
18604            font_size: Some(MINIMAP_FONT_SIZE),
18605            font_weight: Some(MINIMAP_FONT_WEIGHT),
18606            ..Default::default()
18607        });
18608        minimap.update_minimap_configuration(minimap_settings, cx);
18609        cx.new(|_| minimap)
18610    }
18611
18612    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18613        let current_line_highlight = minimap_settings
18614            .current_line_highlight
18615            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18616        self.set_current_line_highlight(Some(current_line_highlight));
18617    }
18618
18619    pub fn minimap(&self) -> Option<&Entity<Self>> {
18620        self.minimap
18621            .as_ref()
18622            .filter(|_| self.minimap_visibility.visible())
18623    }
18624
18625    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18626        let mut wrap_guides = smallvec![];
18627
18628        if self.show_wrap_guides == Some(false) {
18629            return wrap_guides;
18630        }
18631
18632        let settings = self.buffer.read(cx).language_settings(cx);
18633        if settings.show_wrap_guides {
18634            match self.soft_wrap_mode(cx) {
18635                SoftWrap::Column(soft_wrap) => {
18636                    wrap_guides.push((soft_wrap as usize, true));
18637                }
18638                SoftWrap::Bounded(soft_wrap) => {
18639                    wrap_guides.push((soft_wrap as usize, true));
18640                }
18641                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18642            }
18643            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18644        }
18645
18646        wrap_guides
18647    }
18648
18649    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18650        let settings = self.buffer.read(cx).language_settings(cx);
18651        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18652        match mode {
18653            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18654                SoftWrap::None
18655            }
18656            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18657            language_settings::SoftWrap::PreferredLineLength => {
18658                SoftWrap::Column(settings.preferred_line_length)
18659            }
18660            language_settings::SoftWrap::Bounded => {
18661                SoftWrap::Bounded(settings.preferred_line_length)
18662            }
18663        }
18664    }
18665
18666    pub fn set_soft_wrap_mode(
18667        &mut self,
18668        mode: language_settings::SoftWrap,
18669
18670        cx: &mut Context<Self>,
18671    ) {
18672        self.soft_wrap_mode_override = Some(mode);
18673        cx.notify();
18674    }
18675
18676    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18677        self.hard_wrap = hard_wrap;
18678        cx.notify();
18679    }
18680
18681    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18682        self.text_style_refinement = Some(style);
18683    }
18684
18685    /// called by the Element so we know what style we were most recently rendered with.
18686    pub(crate) fn set_style(
18687        &mut self,
18688        style: EditorStyle,
18689        window: &mut Window,
18690        cx: &mut Context<Self>,
18691    ) {
18692        // We intentionally do not inform the display map about the minimap style
18693        // so that wrapping is not recalculated and stays consistent for the editor
18694        // and its linked minimap.
18695        if !self.mode.is_minimap() {
18696            let rem_size = window.rem_size();
18697            self.display_map.update(cx, |map, cx| {
18698                map.set_font(
18699                    style.text.font(),
18700                    style.text.font_size.to_pixels(rem_size),
18701                    cx,
18702                )
18703            });
18704        }
18705        self.style = Some(style);
18706    }
18707
18708    pub fn style(&self) -> Option<&EditorStyle> {
18709        self.style.as_ref()
18710    }
18711
18712    // Called by the element. This method is not designed to be called outside of the editor
18713    // element's layout code because it does not notify when rewrapping is computed synchronously.
18714    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18715        self.display_map
18716            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18717    }
18718
18719    pub fn set_soft_wrap(&mut self) {
18720        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18721    }
18722
18723    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18724        if self.soft_wrap_mode_override.is_some() {
18725            self.soft_wrap_mode_override.take();
18726        } else {
18727            let soft_wrap = match self.soft_wrap_mode(cx) {
18728                SoftWrap::GitDiff => return,
18729                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18730                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18731                    language_settings::SoftWrap::None
18732                }
18733            };
18734            self.soft_wrap_mode_override = Some(soft_wrap);
18735        }
18736        cx.notify();
18737    }
18738
18739    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18740        let Some(workspace) = self.workspace() else {
18741            return;
18742        };
18743        let fs = workspace.read(cx).app_state().fs.clone();
18744        let current_show = TabBarSettings::get_global(cx).show;
18745        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18746            setting.show = Some(!current_show);
18747        });
18748    }
18749
18750    pub fn toggle_indent_guides(
18751        &mut self,
18752        _: &ToggleIndentGuides,
18753        _: &mut Window,
18754        cx: &mut Context<Self>,
18755    ) {
18756        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18757            self.buffer
18758                .read(cx)
18759                .language_settings(cx)
18760                .indent_guides
18761                .enabled
18762        });
18763        self.show_indent_guides = Some(!currently_enabled);
18764        cx.notify();
18765    }
18766
18767    fn should_show_indent_guides(&self) -> Option<bool> {
18768        self.show_indent_guides
18769    }
18770
18771    pub fn toggle_line_numbers(
18772        &mut self,
18773        _: &ToggleLineNumbers,
18774        _: &mut Window,
18775        cx: &mut Context<Self>,
18776    ) {
18777        let mut editor_settings = EditorSettings::get_global(cx).clone();
18778        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18779        EditorSettings::override_global(editor_settings, cx);
18780    }
18781
18782    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18783        if let Some(show_line_numbers) = self.show_line_numbers {
18784            return show_line_numbers;
18785        }
18786        EditorSettings::get_global(cx).gutter.line_numbers
18787    }
18788
18789    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18790        self.use_relative_line_numbers
18791            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18792    }
18793
18794    pub fn toggle_relative_line_numbers(
18795        &mut self,
18796        _: &ToggleRelativeLineNumbers,
18797        _: &mut Window,
18798        cx: &mut Context<Self>,
18799    ) {
18800        let is_relative = self.should_use_relative_line_numbers(cx);
18801        self.set_relative_line_number(Some(!is_relative), cx)
18802    }
18803
18804    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18805        self.use_relative_line_numbers = is_relative;
18806        cx.notify();
18807    }
18808
18809    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18810        self.show_gutter = show_gutter;
18811        cx.notify();
18812    }
18813
18814    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18815        self.show_scrollbars = ScrollbarAxes {
18816            horizontal: show,
18817            vertical: show,
18818        };
18819        cx.notify();
18820    }
18821
18822    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18823        self.show_scrollbars.vertical = show;
18824        cx.notify();
18825    }
18826
18827    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18828        self.show_scrollbars.horizontal = show;
18829        cx.notify();
18830    }
18831
18832    pub fn set_minimap_visibility(
18833        &mut self,
18834        minimap_visibility: MinimapVisibility,
18835        window: &mut Window,
18836        cx: &mut Context<Self>,
18837    ) {
18838        if self.minimap_visibility != minimap_visibility {
18839            if minimap_visibility.visible() && self.minimap.is_none() {
18840                let minimap_settings = EditorSettings::get_global(cx).minimap;
18841                self.minimap =
18842                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18843            }
18844            self.minimap_visibility = minimap_visibility;
18845            cx.notify();
18846        }
18847    }
18848
18849    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18850        self.set_show_scrollbars(false, cx);
18851        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18852    }
18853
18854    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18855        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18856    }
18857
18858    /// Normally the text in full mode and auto height editors is padded on the
18859    /// left side by roughly half a character width for improved hit testing.
18860    ///
18861    /// Use this method to disable this for cases where this is not wanted (e.g.
18862    /// if you want to align the editor text with some other text above or below)
18863    /// or if you want to add this padding to single-line editors.
18864    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18865        self.offset_content = offset_content;
18866        cx.notify();
18867    }
18868
18869    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18870        self.show_line_numbers = Some(show_line_numbers);
18871        cx.notify();
18872    }
18873
18874    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18875        self.disable_expand_excerpt_buttons = true;
18876        cx.notify();
18877    }
18878
18879    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18880        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18881        cx.notify();
18882    }
18883
18884    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18885        self.show_code_actions = Some(show_code_actions);
18886        cx.notify();
18887    }
18888
18889    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18890        self.show_runnables = Some(show_runnables);
18891        cx.notify();
18892    }
18893
18894    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18895        self.show_breakpoints = Some(show_breakpoints);
18896        cx.notify();
18897    }
18898
18899    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18900        if self.display_map.read(cx).masked != masked {
18901            self.display_map.update(cx, |map, _| map.masked = masked);
18902        }
18903        cx.notify()
18904    }
18905
18906    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18907        self.show_wrap_guides = Some(show_wrap_guides);
18908        cx.notify();
18909    }
18910
18911    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18912        self.show_indent_guides = Some(show_indent_guides);
18913        cx.notify();
18914    }
18915
18916    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18917        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18918            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18919                && let Some(dir) = file.abs_path(cx).parent()
18920            {
18921                return Some(dir.to_owned());
18922            }
18923
18924            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18925                return Some(project_path.path.to_path_buf());
18926            }
18927        }
18928
18929        None
18930    }
18931
18932    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18933        self.active_excerpt(cx)?
18934            .1
18935            .read(cx)
18936            .file()
18937            .and_then(|f| f.as_local())
18938    }
18939
18940    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18941        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18942            let buffer = buffer.read(cx);
18943            if let Some(project_path) = buffer.project_path(cx) {
18944                let project = self.project()?.read(cx);
18945                project.absolute_path(&project_path, cx)
18946            } else {
18947                buffer
18948                    .file()
18949                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18950            }
18951        })
18952    }
18953
18954    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18955        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18956            let project_path = buffer.read(cx).project_path(cx)?;
18957            let project = self.project()?.read(cx);
18958            let entry = project.entry_for_path(&project_path, cx)?;
18959            let path = entry.path.to_path_buf();
18960            Some(path)
18961        })
18962    }
18963
18964    pub fn reveal_in_finder(
18965        &mut self,
18966        _: &RevealInFileManager,
18967        _window: &mut Window,
18968        cx: &mut Context<Self>,
18969    ) {
18970        if let Some(target) = self.target_file(cx) {
18971            cx.reveal_path(&target.abs_path(cx));
18972        }
18973    }
18974
18975    pub fn copy_path(
18976        &mut self,
18977        _: &zed_actions::workspace::CopyPath,
18978        _window: &mut Window,
18979        cx: &mut Context<Self>,
18980    ) {
18981        if let Some(path) = self.target_file_abs_path(cx)
18982            && let Some(path) = path.to_str()
18983        {
18984            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18985        }
18986    }
18987
18988    pub fn copy_relative_path(
18989        &mut self,
18990        _: &zed_actions::workspace::CopyRelativePath,
18991        _window: &mut Window,
18992        cx: &mut Context<Self>,
18993    ) {
18994        if let Some(path) = self.target_file_path(cx)
18995            && let Some(path) = path.to_str()
18996        {
18997            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18998        }
18999    }
19000
19001    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19002        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19003            buffer.read(cx).project_path(cx)
19004        } else {
19005            None
19006        }
19007    }
19008
19009    // Returns true if the editor handled a go-to-line request
19010    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19011        maybe!({
19012            let breakpoint_store = self.breakpoint_store.as_ref()?;
19013
19014            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19015            else {
19016                self.clear_row_highlights::<ActiveDebugLine>();
19017                return None;
19018            };
19019
19020            let position = active_stack_frame.position;
19021            let buffer_id = position.buffer_id?;
19022            let snapshot = self
19023                .project
19024                .as_ref()?
19025                .read(cx)
19026                .buffer_for_id(buffer_id, cx)?
19027                .read(cx)
19028                .snapshot();
19029
19030            let mut handled = false;
19031            for (id, ExcerptRange { context, .. }) in
19032                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19033            {
19034                if context.start.cmp(&position, &snapshot).is_ge()
19035                    || context.end.cmp(&position, &snapshot).is_lt()
19036                {
19037                    continue;
19038                }
19039                let snapshot = self.buffer.read(cx).snapshot(cx);
19040                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19041
19042                handled = true;
19043                self.clear_row_highlights::<ActiveDebugLine>();
19044
19045                self.go_to_line::<ActiveDebugLine>(
19046                    multibuffer_anchor,
19047                    Some(cx.theme().colors().editor_debugger_active_line_background),
19048                    window,
19049                    cx,
19050                );
19051
19052                cx.notify();
19053            }
19054
19055            handled.then_some(())
19056        })
19057        .is_some()
19058    }
19059
19060    pub fn copy_file_name_without_extension(
19061        &mut self,
19062        _: &CopyFileNameWithoutExtension,
19063        _: &mut Window,
19064        cx: &mut Context<Self>,
19065    ) {
19066        if let Some(file) = self.target_file(cx)
19067            && let Some(file_stem) = file.path().file_stem()
19068            && let Some(name) = file_stem.to_str()
19069        {
19070            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19071        }
19072    }
19073
19074    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19075        if let Some(file) = self.target_file(cx)
19076            && let Some(file_name) = file.path().file_name()
19077            && let Some(name) = file_name.to_str()
19078        {
19079            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19080        }
19081    }
19082
19083    pub fn toggle_git_blame(
19084        &mut self,
19085        _: &::git::Blame,
19086        window: &mut Window,
19087        cx: &mut Context<Self>,
19088    ) {
19089        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19090
19091        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19092            self.start_git_blame(true, window, cx);
19093        }
19094
19095        cx.notify();
19096    }
19097
19098    pub fn toggle_git_blame_inline(
19099        &mut self,
19100        _: &ToggleGitBlameInline,
19101        window: &mut Window,
19102        cx: &mut Context<Self>,
19103    ) {
19104        self.toggle_git_blame_inline_internal(true, window, cx);
19105        cx.notify();
19106    }
19107
19108    pub fn open_git_blame_commit(
19109        &mut self,
19110        _: &OpenGitBlameCommit,
19111        window: &mut Window,
19112        cx: &mut Context<Self>,
19113    ) {
19114        self.open_git_blame_commit_internal(window, cx);
19115    }
19116
19117    fn open_git_blame_commit_internal(
19118        &mut self,
19119        window: &mut Window,
19120        cx: &mut Context<Self>,
19121    ) -> Option<()> {
19122        let blame = self.blame.as_ref()?;
19123        let snapshot = self.snapshot(window, cx);
19124        let cursor = self.selections.newest::<Point>(cx).head();
19125        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19126        let (_, blame_entry) = blame
19127            .update(cx, |blame, cx| {
19128                blame
19129                    .blame_for_rows(
19130                        &[RowInfo {
19131                            buffer_id: Some(buffer.remote_id()),
19132                            buffer_row: Some(point.row),
19133                            ..Default::default()
19134                        }],
19135                        cx,
19136                    )
19137                    .next()
19138            })
19139            .flatten()?;
19140        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19141        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19142        let workspace = self.workspace()?.downgrade();
19143        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19144        None
19145    }
19146
19147    pub fn git_blame_inline_enabled(&self) -> bool {
19148        self.git_blame_inline_enabled
19149    }
19150
19151    pub fn toggle_selection_menu(
19152        &mut self,
19153        _: &ToggleSelectionMenu,
19154        _: &mut Window,
19155        cx: &mut Context<Self>,
19156    ) {
19157        self.show_selection_menu = self
19158            .show_selection_menu
19159            .map(|show_selections_menu| !show_selections_menu)
19160            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19161
19162        cx.notify();
19163    }
19164
19165    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19166        self.show_selection_menu
19167            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19168    }
19169
19170    fn start_git_blame(
19171        &mut self,
19172        user_triggered: bool,
19173        window: &mut Window,
19174        cx: &mut Context<Self>,
19175    ) {
19176        if let Some(project) = self.project() {
19177            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19178                && buffer.read(cx).file().is_none()
19179            {
19180                return;
19181            }
19182
19183            let focused = self.focus_handle(cx).contains_focused(window, cx);
19184
19185            let project = project.clone();
19186            let blame = cx
19187                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19188            self.blame_subscription =
19189                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19190            self.blame = Some(blame);
19191        }
19192    }
19193
19194    fn toggle_git_blame_inline_internal(
19195        &mut self,
19196        user_triggered: bool,
19197        window: &mut Window,
19198        cx: &mut Context<Self>,
19199    ) {
19200        if self.git_blame_inline_enabled {
19201            self.git_blame_inline_enabled = false;
19202            self.show_git_blame_inline = false;
19203            self.show_git_blame_inline_delay_task.take();
19204        } else {
19205            self.git_blame_inline_enabled = true;
19206            self.start_git_blame_inline(user_triggered, window, cx);
19207        }
19208
19209        cx.notify();
19210    }
19211
19212    fn start_git_blame_inline(
19213        &mut self,
19214        user_triggered: bool,
19215        window: &mut Window,
19216        cx: &mut Context<Self>,
19217    ) {
19218        self.start_git_blame(user_triggered, window, cx);
19219
19220        if ProjectSettings::get_global(cx)
19221            .git
19222            .inline_blame_delay()
19223            .is_some()
19224        {
19225            self.start_inline_blame_timer(window, cx);
19226        } else {
19227            self.show_git_blame_inline = true
19228        }
19229    }
19230
19231    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19232        self.blame.as_ref()
19233    }
19234
19235    pub fn show_git_blame_gutter(&self) -> bool {
19236        self.show_git_blame_gutter
19237    }
19238
19239    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19240        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19241    }
19242
19243    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19244        self.show_git_blame_inline
19245            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19246            && !self.newest_selection_head_on_empty_line(cx)
19247            && self.has_blame_entries(cx)
19248    }
19249
19250    fn has_blame_entries(&self, cx: &App) -> bool {
19251        self.blame()
19252            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19253    }
19254
19255    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19256        let cursor_anchor = self.selections.newest_anchor().head();
19257
19258        let snapshot = self.buffer.read(cx).snapshot(cx);
19259        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19260
19261        snapshot.line_len(buffer_row) == 0
19262    }
19263
19264    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19265        let buffer_and_selection = maybe!({
19266            let selection = self.selections.newest::<Point>(cx);
19267            let selection_range = selection.range();
19268
19269            let multi_buffer = self.buffer().read(cx);
19270            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19271            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19272
19273            let (buffer, range, _) = if selection.reversed {
19274                buffer_ranges.first()
19275            } else {
19276                buffer_ranges.last()
19277            }?;
19278
19279            let selection = text::ToPoint::to_point(&range.start, buffer).row
19280                ..text::ToPoint::to_point(&range.end, buffer).row;
19281            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19282        });
19283
19284        let Some((buffer, selection)) = buffer_and_selection else {
19285            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19286        };
19287
19288        let Some(project) = self.project() else {
19289            return Task::ready(Err(anyhow!("editor does not have project")));
19290        };
19291
19292        project.update(cx, |project, cx| {
19293            project.get_permalink_to_line(&buffer, selection, cx)
19294        })
19295    }
19296
19297    pub fn copy_permalink_to_line(
19298        &mut self,
19299        _: &CopyPermalinkToLine,
19300        window: &mut Window,
19301        cx: &mut Context<Self>,
19302    ) {
19303        let permalink_task = self.get_permalink_to_line(cx);
19304        let workspace = self.workspace();
19305
19306        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19307            Ok(permalink) => {
19308                cx.update(|_, cx| {
19309                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19310                })
19311                .ok();
19312            }
19313            Err(err) => {
19314                let message = format!("Failed to copy permalink: {err}");
19315
19316                anyhow::Result::<()>::Err(err).log_err();
19317
19318                if let Some(workspace) = workspace {
19319                    workspace
19320                        .update_in(cx, |workspace, _, cx| {
19321                            struct CopyPermalinkToLine;
19322
19323                            workspace.show_toast(
19324                                Toast::new(
19325                                    NotificationId::unique::<CopyPermalinkToLine>(),
19326                                    message,
19327                                ),
19328                                cx,
19329                            )
19330                        })
19331                        .ok();
19332                }
19333            }
19334        })
19335        .detach();
19336    }
19337
19338    pub fn copy_file_location(
19339        &mut self,
19340        _: &CopyFileLocation,
19341        _: &mut Window,
19342        cx: &mut Context<Self>,
19343    ) {
19344        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19345        if let Some(file) = self.target_file(cx)
19346            && let Some(path) = file.path().to_str()
19347        {
19348            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19349        }
19350    }
19351
19352    pub fn open_permalink_to_line(
19353        &mut self,
19354        _: &OpenPermalinkToLine,
19355        window: &mut Window,
19356        cx: &mut Context<Self>,
19357    ) {
19358        let permalink_task = self.get_permalink_to_line(cx);
19359        let workspace = self.workspace();
19360
19361        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19362            Ok(permalink) => {
19363                cx.update(|_, cx| {
19364                    cx.open_url(permalink.as_ref());
19365                })
19366                .ok();
19367            }
19368            Err(err) => {
19369                let message = format!("Failed to open permalink: {err}");
19370
19371                anyhow::Result::<()>::Err(err).log_err();
19372
19373                if let Some(workspace) = workspace {
19374                    workspace
19375                        .update(cx, |workspace, cx| {
19376                            struct OpenPermalinkToLine;
19377
19378                            workspace.show_toast(
19379                                Toast::new(
19380                                    NotificationId::unique::<OpenPermalinkToLine>(),
19381                                    message,
19382                                ),
19383                                cx,
19384                            )
19385                        })
19386                        .ok();
19387                }
19388            }
19389        })
19390        .detach();
19391    }
19392
19393    pub fn insert_uuid_v4(
19394        &mut self,
19395        _: &InsertUuidV4,
19396        window: &mut Window,
19397        cx: &mut Context<Self>,
19398    ) {
19399        self.insert_uuid(UuidVersion::V4, window, cx);
19400    }
19401
19402    pub fn insert_uuid_v7(
19403        &mut self,
19404        _: &InsertUuidV7,
19405        window: &mut Window,
19406        cx: &mut Context<Self>,
19407    ) {
19408        self.insert_uuid(UuidVersion::V7, window, cx);
19409    }
19410
19411    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19412        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19413        self.transact(window, cx, |this, window, cx| {
19414            let edits = this
19415                .selections
19416                .all::<Point>(cx)
19417                .into_iter()
19418                .map(|selection| {
19419                    let uuid = match version {
19420                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19421                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19422                    };
19423
19424                    (selection.range(), uuid.to_string())
19425                });
19426            this.edit(edits, cx);
19427            this.refresh_edit_prediction(true, false, window, cx);
19428        });
19429    }
19430
19431    pub fn open_selections_in_multibuffer(
19432        &mut self,
19433        _: &OpenSelectionsInMultibuffer,
19434        window: &mut Window,
19435        cx: &mut Context<Self>,
19436    ) {
19437        let multibuffer = self.buffer.read(cx);
19438
19439        let Some(buffer) = multibuffer.as_singleton() else {
19440            return;
19441        };
19442
19443        let Some(workspace) = self.workspace() else {
19444            return;
19445        };
19446
19447        let title = multibuffer.title(cx).to_string();
19448
19449        let locations = self
19450            .selections
19451            .all_anchors(cx)
19452            .iter()
19453            .map(|selection| Location {
19454                buffer: buffer.clone(),
19455                range: selection.start.text_anchor..selection.end.text_anchor,
19456            })
19457            .collect::<Vec<_>>();
19458
19459        cx.spawn_in(window, async move |_, cx| {
19460            workspace.update_in(cx, |workspace, window, cx| {
19461                Self::open_locations_in_multibuffer(
19462                    workspace,
19463                    locations,
19464                    format!("Selections for '{title}'"),
19465                    false,
19466                    MultibufferSelectionMode::All,
19467                    window,
19468                    cx,
19469                );
19470            })
19471        })
19472        .detach();
19473    }
19474
19475    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19476    /// last highlight added will be used.
19477    ///
19478    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19479    pub fn highlight_rows<T: 'static>(
19480        &mut self,
19481        range: Range<Anchor>,
19482        color: Hsla,
19483        options: RowHighlightOptions,
19484        cx: &mut Context<Self>,
19485    ) {
19486        let snapshot = self.buffer().read(cx).snapshot(cx);
19487        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19488        let ix = row_highlights.binary_search_by(|highlight| {
19489            Ordering::Equal
19490                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19491                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19492        });
19493
19494        if let Err(mut ix) = ix {
19495            let index = post_inc(&mut self.highlight_order);
19496
19497            // If this range intersects with the preceding highlight, then merge it with
19498            // the preceding highlight. Otherwise insert a new highlight.
19499            let mut merged = false;
19500            if ix > 0 {
19501                let prev_highlight = &mut row_highlights[ix - 1];
19502                if prev_highlight
19503                    .range
19504                    .end
19505                    .cmp(&range.start, &snapshot)
19506                    .is_ge()
19507                {
19508                    ix -= 1;
19509                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19510                        prev_highlight.range.end = range.end;
19511                    }
19512                    merged = true;
19513                    prev_highlight.index = index;
19514                    prev_highlight.color = color;
19515                    prev_highlight.options = options;
19516                }
19517            }
19518
19519            if !merged {
19520                row_highlights.insert(
19521                    ix,
19522                    RowHighlight {
19523                        range,
19524                        index,
19525                        color,
19526                        options,
19527                        type_id: TypeId::of::<T>(),
19528                    },
19529                );
19530            }
19531
19532            // If any of the following highlights intersect with this one, merge them.
19533            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19534                let highlight = &row_highlights[ix];
19535                if next_highlight
19536                    .range
19537                    .start
19538                    .cmp(&highlight.range.end, &snapshot)
19539                    .is_le()
19540                {
19541                    if next_highlight
19542                        .range
19543                        .end
19544                        .cmp(&highlight.range.end, &snapshot)
19545                        .is_gt()
19546                    {
19547                        row_highlights[ix].range.end = next_highlight.range.end;
19548                    }
19549                    row_highlights.remove(ix + 1);
19550                } else {
19551                    break;
19552                }
19553            }
19554        }
19555    }
19556
19557    /// Remove any highlighted row ranges of the given type that intersect the
19558    /// given ranges.
19559    pub fn remove_highlighted_rows<T: 'static>(
19560        &mut self,
19561        ranges_to_remove: Vec<Range<Anchor>>,
19562        cx: &mut Context<Self>,
19563    ) {
19564        let snapshot = self.buffer().read(cx).snapshot(cx);
19565        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19566        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19567        row_highlights.retain(|highlight| {
19568            while let Some(range_to_remove) = ranges_to_remove.peek() {
19569                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19570                    Ordering::Less | Ordering::Equal => {
19571                        ranges_to_remove.next();
19572                    }
19573                    Ordering::Greater => {
19574                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19575                            Ordering::Less | Ordering::Equal => {
19576                                return false;
19577                            }
19578                            Ordering::Greater => break,
19579                        }
19580                    }
19581                }
19582            }
19583
19584            true
19585        })
19586    }
19587
19588    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19589    pub fn clear_row_highlights<T: 'static>(&mut self) {
19590        self.highlighted_rows.remove(&TypeId::of::<T>());
19591    }
19592
19593    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19594    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19595        self.highlighted_rows
19596            .get(&TypeId::of::<T>())
19597            .map_or(&[] as &[_], |vec| vec.as_slice())
19598            .iter()
19599            .map(|highlight| (highlight.range.clone(), highlight.color))
19600    }
19601
19602    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19603    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19604    /// Allows to ignore certain kinds of highlights.
19605    pub fn highlighted_display_rows(
19606        &self,
19607        window: &mut Window,
19608        cx: &mut App,
19609    ) -> BTreeMap<DisplayRow, LineHighlight> {
19610        let snapshot = self.snapshot(window, cx);
19611        let mut used_highlight_orders = HashMap::default();
19612        self.highlighted_rows
19613            .iter()
19614            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19615            .fold(
19616                BTreeMap::<DisplayRow, LineHighlight>::new(),
19617                |mut unique_rows, highlight| {
19618                    let start = highlight.range.start.to_display_point(&snapshot);
19619                    let end = highlight.range.end.to_display_point(&snapshot);
19620                    let start_row = start.row().0;
19621                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19622                        && end.column() == 0
19623                    {
19624                        end.row().0.saturating_sub(1)
19625                    } else {
19626                        end.row().0
19627                    };
19628                    for row in start_row..=end_row {
19629                        let used_index =
19630                            used_highlight_orders.entry(row).or_insert(highlight.index);
19631                        if highlight.index >= *used_index {
19632                            *used_index = highlight.index;
19633                            unique_rows.insert(
19634                                DisplayRow(row),
19635                                LineHighlight {
19636                                    include_gutter: highlight.options.include_gutter,
19637                                    border: None,
19638                                    background: highlight.color.into(),
19639                                    type_id: Some(highlight.type_id),
19640                                },
19641                            );
19642                        }
19643                    }
19644                    unique_rows
19645                },
19646            )
19647    }
19648
19649    pub fn highlighted_display_row_for_autoscroll(
19650        &self,
19651        snapshot: &DisplaySnapshot,
19652    ) -> Option<DisplayRow> {
19653        self.highlighted_rows
19654            .values()
19655            .flat_map(|highlighted_rows| highlighted_rows.iter())
19656            .filter_map(|highlight| {
19657                if highlight.options.autoscroll {
19658                    Some(highlight.range.start.to_display_point(snapshot).row())
19659                } else {
19660                    None
19661                }
19662            })
19663            .min()
19664    }
19665
19666    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19667        self.highlight_background::<SearchWithinRange>(
19668            ranges,
19669            |colors| colors.colors().editor_document_highlight_read_background,
19670            cx,
19671        )
19672    }
19673
19674    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19675        self.breadcrumb_header = Some(new_header);
19676    }
19677
19678    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19679        self.clear_background_highlights::<SearchWithinRange>(cx);
19680    }
19681
19682    pub fn highlight_background<T: 'static>(
19683        &mut self,
19684        ranges: &[Range<Anchor>],
19685        color_fetcher: fn(&Theme) -> Hsla,
19686        cx: &mut Context<Self>,
19687    ) {
19688        self.background_highlights.insert(
19689            HighlightKey::Type(TypeId::of::<T>()),
19690            (color_fetcher, Arc::from(ranges)),
19691        );
19692        self.scrollbar_marker_state.dirty = true;
19693        cx.notify();
19694    }
19695
19696    pub fn highlight_background_key<T: 'static>(
19697        &mut self,
19698        key: usize,
19699        ranges: &[Range<Anchor>],
19700        color_fetcher: fn(&Theme) -> Hsla,
19701        cx: &mut Context<Self>,
19702    ) {
19703        self.background_highlights.insert(
19704            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19705            (color_fetcher, Arc::from(ranges)),
19706        );
19707        self.scrollbar_marker_state.dirty = true;
19708        cx.notify();
19709    }
19710
19711    pub fn clear_background_highlights<T: 'static>(
19712        &mut self,
19713        cx: &mut Context<Self>,
19714    ) -> Option<BackgroundHighlight> {
19715        let text_highlights = self
19716            .background_highlights
19717            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19718        if !text_highlights.1.is_empty() {
19719            self.scrollbar_marker_state.dirty = true;
19720            cx.notify();
19721        }
19722        Some(text_highlights)
19723    }
19724
19725    pub fn highlight_gutter<T: 'static>(
19726        &mut self,
19727        ranges: impl Into<Vec<Range<Anchor>>>,
19728        color_fetcher: fn(&App) -> Hsla,
19729        cx: &mut Context<Self>,
19730    ) {
19731        self.gutter_highlights
19732            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19733        cx.notify();
19734    }
19735
19736    pub fn clear_gutter_highlights<T: 'static>(
19737        &mut self,
19738        cx: &mut Context<Self>,
19739    ) -> Option<GutterHighlight> {
19740        cx.notify();
19741        self.gutter_highlights.remove(&TypeId::of::<T>())
19742    }
19743
19744    pub fn insert_gutter_highlight<T: 'static>(
19745        &mut self,
19746        range: Range<Anchor>,
19747        color_fetcher: fn(&App) -> Hsla,
19748        cx: &mut Context<Self>,
19749    ) {
19750        let snapshot = self.buffer().read(cx).snapshot(cx);
19751        let mut highlights = self
19752            .gutter_highlights
19753            .remove(&TypeId::of::<T>())
19754            .map(|(_, highlights)| highlights)
19755            .unwrap_or_default();
19756        let ix = highlights.binary_search_by(|highlight| {
19757            Ordering::Equal
19758                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19759                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19760        });
19761        if let Err(ix) = ix {
19762            highlights.insert(ix, range);
19763        }
19764        self.gutter_highlights
19765            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19766    }
19767
19768    pub fn remove_gutter_highlights<T: 'static>(
19769        &mut self,
19770        ranges_to_remove: Vec<Range<Anchor>>,
19771        cx: &mut Context<Self>,
19772    ) {
19773        let snapshot = self.buffer().read(cx).snapshot(cx);
19774        let Some((color_fetcher, mut gutter_highlights)) =
19775            self.gutter_highlights.remove(&TypeId::of::<T>())
19776        else {
19777            return;
19778        };
19779        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19780        gutter_highlights.retain(|highlight| {
19781            while let Some(range_to_remove) = ranges_to_remove.peek() {
19782                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19783                    Ordering::Less | Ordering::Equal => {
19784                        ranges_to_remove.next();
19785                    }
19786                    Ordering::Greater => {
19787                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19788                            Ordering::Less | Ordering::Equal => {
19789                                return false;
19790                            }
19791                            Ordering::Greater => break,
19792                        }
19793                    }
19794                }
19795            }
19796
19797            true
19798        });
19799        self.gutter_highlights
19800            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19801    }
19802
19803    #[cfg(feature = "test-support")]
19804    pub fn all_text_highlights(
19805        &self,
19806        window: &mut Window,
19807        cx: &mut Context<Self>,
19808    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19809        let snapshot = self.snapshot(window, cx);
19810        self.display_map.update(cx, |display_map, _| {
19811            display_map
19812                .all_text_highlights()
19813                .map(|highlight| {
19814                    let (style, ranges) = highlight.as_ref();
19815                    (
19816                        *style,
19817                        ranges
19818                            .iter()
19819                            .map(|range| range.clone().to_display_points(&snapshot))
19820                            .collect(),
19821                    )
19822                })
19823                .collect()
19824        })
19825    }
19826
19827    #[cfg(feature = "test-support")]
19828    pub fn all_text_background_highlights(
19829        &self,
19830        window: &mut Window,
19831        cx: &mut Context<Self>,
19832    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19833        let snapshot = self.snapshot(window, cx);
19834        let buffer = &snapshot.buffer_snapshot;
19835        let start = buffer.anchor_before(0);
19836        let end = buffer.anchor_after(buffer.len());
19837        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
19838    }
19839
19840    #[cfg(any(test, feature = "test-support"))]
19841    pub fn sorted_background_highlights_in_range(
19842        &self,
19843        search_range: Range<Anchor>,
19844        display_snapshot: &DisplaySnapshot,
19845        theme: &Theme,
19846    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19847        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
19848        res.sort_by(|a, b| {
19849            a.0.start
19850                .cmp(&b.0.start)
19851                .then_with(|| a.0.end.cmp(&b.0.end))
19852                .then_with(|| a.1.cmp(&b.1))
19853        });
19854        res
19855    }
19856
19857    #[cfg(feature = "test-support")]
19858    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19859        let snapshot = self.buffer().read(cx).snapshot(cx);
19860
19861        let highlights = self
19862            .background_highlights
19863            .get(&HighlightKey::Type(TypeId::of::<
19864                items::BufferSearchHighlights,
19865            >()));
19866
19867        if let Some((_color, ranges)) = highlights {
19868            ranges
19869                .iter()
19870                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19871                .collect_vec()
19872        } else {
19873            vec![]
19874        }
19875    }
19876
19877    fn document_highlights_for_position<'a>(
19878        &'a self,
19879        position: Anchor,
19880        buffer: &'a MultiBufferSnapshot,
19881    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19882        let read_highlights = self
19883            .background_highlights
19884            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19885            .map(|h| &h.1);
19886        let write_highlights = self
19887            .background_highlights
19888            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19889            .map(|h| &h.1);
19890        let left_position = position.bias_left(buffer);
19891        let right_position = position.bias_right(buffer);
19892        read_highlights
19893            .into_iter()
19894            .chain(write_highlights)
19895            .flat_map(move |ranges| {
19896                let start_ix = match ranges.binary_search_by(|probe| {
19897                    let cmp = probe.end.cmp(&left_position, buffer);
19898                    if cmp.is_ge() {
19899                        Ordering::Greater
19900                    } else {
19901                        Ordering::Less
19902                    }
19903                }) {
19904                    Ok(i) | Err(i) => i,
19905                };
19906
19907                ranges[start_ix..]
19908                    .iter()
19909                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19910            })
19911    }
19912
19913    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19914        self.background_highlights
19915            .get(&HighlightKey::Type(TypeId::of::<T>()))
19916            .is_some_and(|(_, highlights)| !highlights.is_empty())
19917    }
19918
19919    /// Returns all background highlights for a given range.
19920    ///
19921    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
19922    pub fn background_highlights_in_range(
19923        &self,
19924        search_range: Range<Anchor>,
19925        display_snapshot: &DisplaySnapshot,
19926        theme: &Theme,
19927    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19928        let mut results = Vec::new();
19929        for (color_fetcher, ranges) in self.background_highlights.values() {
19930            let color = color_fetcher(theme);
19931            let start_ix = match ranges.binary_search_by(|probe| {
19932                let cmp = probe
19933                    .end
19934                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19935                if cmp.is_gt() {
19936                    Ordering::Greater
19937                } else {
19938                    Ordering::Less
19939                }
19940            }) {
19941                Ok(i) | Err(i) => i,
19942            };
19943            for range in &ranges[start_ix..] {
19944                if range
19945                    .start
19946                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19947                    .is_ge()
19948                {
19949                    break;
19950                }
19951
19952                let start = range.start.to_display_point(display_snapshot);
19953                let end = range.end.to_display_point(display_snapshot);
19954                results.push((start..end, color))
19955            }
19956        }
19957        results
19958    }
19959
19960    pub fn gutter_highlights_in_range(
19961        &self,
19962        search_range: Range<Anchor>,
19963        display_snapshot: &DisplaySnapshot,
19964        cx: &App,
19965    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19966        let mut results = Vec::new();
19967        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19968            let color = color_fetcher(cx);
19969            let start_ix = match ranges.binary_search_by(|probe| {
19970                let cmp = probe
19971                    .end
19972                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19973                if cmp.is_gt() {
19974                    Ordering::Greater
19975                } else {
19976                    Ordering::Less
19977                }
19978            }) {
19979                Ok(i) | Err(i) => i,
19980            };
19981            for range in &ranges[start_ix..] {
19982                if range
19983                    .start
19984                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19985                    .is_ge()
19986                {
19987                    break;
19988                }
19989
19990                let start = range.start.to_display_point(display_snapshot);
19991                let end = range.end.to_display_point(display_snapshot);
19992                results.push((start..end, color))
19993            }
19994        }
19995        results
19996    }
19997
19998    /// Get the text ranges corresponding to the redaction query
19999    pub fn redacted_ranges(
20000        &self,
20001        search_range: Range<Anchor>,
20002        display_snapshot: &DisplaySnapshot,
20003        cx: &App,
20004    ) -> Vec<Range<DisplayPoint>> {
20005        display_snapshot
20006            .buffer_snapshot
20007            .redacted_ranges(search_range, |file| {
20008                if let Some(file) = file {
20009                    file.is_private()
20010                        && EditorSettings::get(
20011                            Some(SettingsLocation {
20012                                worktree_id: file.worktree_id(cx),
20013                                path: file.path().as_ref(),
20014                            }),
20015                            cx,
20016                        )
20017                        .redact_private_values
20018                } else {
20019                    false
20020                }
20021            })
20022            .map(|range| {
20023                range.start.to_display_point(display_snapshot)
20024                    ..range.end.to_display_point(display_snapshot)
20025            })
20026            .collect()
20027    }
20028
20029    pub fn highlight_text_key<T: 'static>(
20030        &mut self,
20031        key: usize,
20032        ranges: Vec<Range<Anchor>>,
20033        style: HighlightStyle,
20034        cx: &mut Context<Self>,
20035    ) {
20036        self.display_map.update(cx, |map, _| {
20037            map.highlight_text(
20038                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20039                ranges,
20040                style,
20041            );
20042        });
20043        cx.notify();
20044    }
20045
20046    pub fn highlight_text<T: 'static>(
20047        &mut self,
20048        ranges: Vec<Range<Anchor>>,
20049        style: HighlightStyle,
20050        cx: &mut Context<Self>,
20051    ) {
20052        self.display_map.update(cx, |map, _| {
20053            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20054        });
20055        cx.notify();
20056    }
20057
20058    pub(crate) fn highlight_inlays<T: 'static>(
20059        &mut self,
20060        highlights: Vec<InlayHighlight>,
20061        style: HighlightStyle,
20062        cx: &mut Context<Self>,
20063    ) {
20064        self.display_map.update(cx, |map, _| {
20065            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20066        });
20067        cx.notify();
20068    }
20069
20070    pub fn text_highlights<'a, T: 'static>(
20071        &'a self,
20072        cx: &'a App,
20073    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20074        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20075    }
20076
20077    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20078        let cleared = self
20079            .display_map
20080            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20081        if cleared {
20082            cx.notify();
20083        }
20084    }
20085
20086    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20087        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20088            && self.focus_handle.is_focused(window)
20089    }
20090
20091    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20092        self.show_cursor_when_unfocused = is_enabled;
20093        cx.notify();
20094    }
20095
20096    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20097        cx.notify();
20098    }
20099
20100    fn on_debug_session_event(
20101        &mut self,
20102        _session: Entity<Session>,
20103        event: &SessionEvent,
20104        cx: &mut Context<Self>,
20105    ) {
20106        if let SessionEvent::InvalidateInlineValue = event {
20107            self.refresh_inline_values(cx);
20108        }
20109    }
20110
20111    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20112        let Some(project) = self.project.clone() else {
20113            return;
20114        };
20115
20116        if !self.inline_value_cache.enabled {
20117            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20118            self.splice_inlays(&inlays, Vec::new(), cx);
20119            return;
20120        }
20121
20122        let current_execution_position = self
20123            .highlighted_rows
20124            .get(&TypeId::of::<ActiveDebugLine>())
20125            .and_then(|lines| lines.last().map(|line| line.range.end));
20126
20127        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20128            let inline_values = editor
20129                .update(cx, |editor, cx| {
20130                    let Some(current_execution_position) = current_execution_position else {
20131                        return Some(Task::ready(Ok(Vec::new())));
20132                    };
20133
20134                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20135                        let snapshot = buffer.snapshot(cx);
20136
20137                        let excerpt = snapshot.excerpt_containing(
20138                            current_execution_position..current_execution_position,
20139                        )?;
20140
20141                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20142                    })?;
20143
20144                    let range =
20145                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20146
20147                    project.inline_values(buffer, range, cx)
20148                })
20149                .ok()
20150                .flatten()?
20151                .await
20152                .context("refreshing debugger inlays")
20153                .log_err()?;
20154
20155            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20156
20157            for (buffer_id, inline_value) in inline_values
20158                .into_iter()
20159                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20160            {
20161                buffer_inline_values
20162                    .entry(buffer_id)
20163                    .or_default()
20164                    .push(inline_value);
20165            }
20166
20167            editor
20168                .update(cx, |editor, cx| {
20169                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20170                    let mut new_inlays = Vec::default();
20171
20172                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20173                        let buffer_id = buffer_snapshot.remote_id();
20174                        buffer_inline_values
20175                            .get(&buffer_id)
20176                            .into_iter()
20177                            .flatten()
20178                            .for_each(|hint| {
20179                                let inlay = Inlay::debugger(
20180                                    post_inc(&mut editor.next_inlay_id),
20181                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20182                                    hint.text(),
20183                                );
20184                                if !inlay.text.chars().contains(&'\n') {
20185                                    new_inlays.push(inlay);
20186                                }
20187                            });
20188                    }
20189
20190                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20191                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20192
20193                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20194                })
20195                .ok()?;
20196            Some(())
20197        });
20198    }
20199
20200    fn on_buffer_event(
20201        &mut self,
20202        multibuffer: &Entity<MultiBuffer>,
20203        event: &multi_buffer::Event,
20204        window: &mut Window,
20205        cx: &mut Context<Self>,
20206    ) {
20207        match event {
20208            multi_buffer::Event::Edited {
20209                singleton_buffer_edited,
20210                edited_buffer,
20211            } => {
20212                self.scrollbar_marker_state.dirty = true;
20213                self.active_indent_guides_state.dirty = true;
20214                self.refresh_active_diagnostics(cx);
20215                self.refresh_code_actions(window, cx);
20216                self.refresh_selected_text_highlights(true, window, cx);
20217                self.refresh_single_line_folds(window, cx);
20218                refresh_matching_bracket_highlights(self, window, cx);
20219                if self.has_active_edit_prediction() {
20220                    self.update_visible_edit_prediction(window, cx);
20221                }
20222                if let Some(project) = self.project.as_ref()
20223                    && let Some(edited_buffer) = edited_buffer
20224                {
20225                    project.update(cx, |project, cx| {
20226                        self.registered_buffers
20227                            .entry(edited_buffer.read(cx).remote_id())
20228                            .or_insert_with(|| {
20229                                project.register_buffer_with_language_servers(edited_buffer, cx)
20230                            });
20231                    });
20232                }
20233                cx.emit(EditorEvent::BufferEdited);
20234                cx.emit(SearchEvent::MatchesInvalidated);
20235
20236                if let Some(buffer) = edited_buffer {
20237                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20238                }
20239
20240                if *singleton_buffer_edited {
20241                    if let Some(buffer) = edited_buffer
20242                        && buffer.read(cx).file().is_none()
20243                    {
20244                        cx.emit(EditorEvent::TitleChanged);
20245                    }
20246                    if let Some(project) = &self.project {
20247                        #[allow(clippy::mutable_key_type)]
20248                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20249                            multibuffer
20250                                .all_buffers()
20251                                .into_iter()
20252                                .filter_map(|buffer| {
20253                                    buffer.update(cx, |buffer, cx| {
20254                                        let language = buffer.language()?;
20255                                        let should_discard = project.update(cx, |project, cx| {
20256                                            project.is_local()
20257                                                && !project.has_language_servers_for(buffer, cx)
20258                                        });
20259                                        should_discard.not().then_some(language.clone())
20260                                    })
20261                                })
20262                                .collect::<HashSet<_>>()
20263                        });
20264                        if !languages_affected.is_empty() {
20265                            self.refresh_inlay_hints(
20266                                InlayHintRefreshReason::BufferEdited(languages_affected),
20267                                cx,
20268                            );
20269                        }
20270                    }
20271                }
20272
20273                let Some(project) = &self.project else { return };
20274                let (telemetry, is_via_ssh) = {
20275                    let project = project.read(cx);
20276                    let telemetry = project.client().telemetry().clone();
20277                    let is_via_ssh = project.is_via_remote_server();
20278                    (telemetry, is_via_ssh)
20279                };
20280                refresh_linked_ranges(self, window, cx);
20281                telemetry.log_edit_event("editor", is_via_ssh);
20282            }
20283            multi_buffer::Event::ExcerptsAdded {
20284                buffer,
20285                predecessor,
20286                excerpts,
20287            } => {
20288                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20289                let buffer_id = buffer.read(cx).remote_id();
20290                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20291                    && let Some(project) = &self.project
20292                {
20293                    update_uncommitted_diff_for_buffer(
20294                        cx.entity(),
20295                        project,
20296                        [buffer.clone()],
20297                        self.buffer.clone(),
20298                        cx,
20299                    )
20300                    .detach();
20301                }
20302                self.update_lsp_data(false, Some(buffer_id), window, cx);
20303                cx.emit(EditorEvent::ExcerptsAdded {
20304                    buffer: buffer.clone(),
20305                    predecessor: *predecessor,
20306                    excerpts: excerpts.clone(),
20307                });
20308                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20309            }
20310            multi_buffer::Event::ExcerptsRemoved {
20311                ids,
20312                removed_buffer_ids,
20313            } => {
20314                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20315                let buffer = self.buffer.read(cx);
20316                self.registered_buffers
20317                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20318                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20319                cx.emit(EditorEvent::ExcerptsRemoved {
20320                    ids: ids.clone(),
20321                    removed_buffer_ids: removed_buffer_ids.clone(),
20322                });
20323            }
20324            multi_buffer::Event::ExcerptsEdited {
20325                excerpt_ids,
20326                buffer_ids,
20327            } => {
20328                self.display_map.update(cx, |map, cx| {
20329                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20330                });
20331                cx.emit(EditorEvent::ExcerptsEdited {
20332                    ids: excerpt_ids.clone(),
20333                });
20334            }
20335            multi_buffer::Event::ExcerptsExpanded { ids } => {
20336                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20337                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20338            }
20339            multi_buffer::Event::Reparsed(buffer_id) => {
20340                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20341                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20342
20343                cx.emit(EditorEvent::Reparsed(*buffer_id));
20344            }
20345            multi_buffer::Event::DiffHunksToggled => {
20346                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20347            }
20348            multi_buffer::Event::LanguageChanged(buffer_id) => {
20349                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20350                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20351                cx.emit(EditorEvent::Reparsed(*buffer_id));
20352                cx.notify();
20353            }
20354            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20355            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20356            multi_buffer::Event::FileHandleChanged
20357            | multi_buffer::Event::Reloaded
20358            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20359            multi_buffer::Event::DiagnosticsUpdated => {
20360                self.update_diagnostics_state(window, cx);
20361            }
20362            _ => {}
20363        };
20364    }
20365
20366    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20367        if !self.diagnostics_enabled() {
20368            return;
20369        }
20370        self.refresh_active_diagnostics(cx);
20371        self.refresh_inline_diagnostics(true, window, cx);
20372        self.scrollbar_marker_state.dirty = true;
20373        cx.notify();
20374    }
20375
20376    pub fn start_temporary_diff_override(&mut self) {
20377        self.load_diff_task.take();
20378        self.temporary_diff_override = true;
20379    }
20380
20381    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20382        self.temporary_diff_override = false;
20383        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20384        self.buffer.update(cx, |buffer, cx| {
20385            buffer.set_all_diff_hunks_collapsed(cx);
20386        });
20387
20388        if let Some(project) = self.project.clone() {
20389            self.load_diff_task = Some(
20390                update_uncommitted_diff_for_buffer(
20391                    cx.entity(),
20392                    &project,
20393                    self.buffer.read(cx).all_buffers(),
20394                    self.buffer.clone(),
20395                    cx,
20396                )
20397                .shared(),
20398            );
20399        }
20400    }
20401
20402    fn on_display_map_changed(
20403        &mut self,
20404        _: Entity<DisplayMap>,
20405        _: &mut Window,
20406        cx: &mut Context<Self>,
20407    ) {
20408        cx.notify();
20409    }
20410
20411    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20412        if self.diagnostics_enabled() {
20413            let new_severity = EditorSettings::get_global(cx)
20414                .diagnostics_max_severity
20415                .unwrap_or(DiagnosticSeverity::Hint);
20416            self.set_max_diagnostics_severity(new_severity, cx);
20417        }
20418        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20419        self.update_edit_prediction_settings(cx);
20420        self.refresh_edit_prediction(true, false, window, cx);
20421        self.refresh_inline_values(cx);
20422        self.refresh_inlay_hints(
20423            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20424                self.selections.newest_anchor().head(),
20425                &self.buffer.read(cx).snapshot(cx),
20426                cx,
20427            )),
20428            cx,
20429        );
20430
20431        let old_cursor_shape = self.cursor_shape;
20432        let old_show_breadcrumbs = self.show_breadcrumbs;
20433
20434        {
20435            let editor_settings = EditorSettings::get_global(cx);
20436            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20437            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20438            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20439            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20440        }
20441
20442        if old_cursor_shape != self.cursor_shape {
20443            cx.emit(EditorEvent::CursorShapeChanged);
20444        }
20445
20446        if old_show_breadcrumbs != self.show_breadcrumbs {
20447            cx.emit(EditorEvent::BreadcrumbsChanged);
20448        }
20449
20450        let project_settings = ProjectSettings::get_global(cx);
20451        self.serialize_dirty_buffers =
20452            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20453
20454        if self.mode.is_full() {
20455            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20456            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20457            if self.show_inline_diagnostics != show_inline_diagnostics {
20458                self.show_inline_diagnostics = show_inline_diagnostics;
20459                self.refresh_inline_diagnostics(false, window, cx);
20460            }
20461
20462            if self.git_blame_inline_enabled != inline_blame_enabled {
20463                self.toggle_git_blame_inline_internal(false, window, cx);
20464            }
20465
20466            let minimap_settings = EditorSettings::get_global(cx).minimap;
20467            if self.minimap_visibility != MinimapVisibility::Disabled {
20468                if self.minimap_visibility.settings_visibility()
20469                    != minimap_settings.minimap_enabled()
20470                {
20471                    self.set_minimap_visibility(
20472                        MinimapVisibility::for_mode(self.mode(), cx),
20473                        window,
20474                        cx,
20475                    );
20476                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20477                    minimap_entity.update(cx, |minimap_editor, cx| {
20478                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20479                    })
20480                }
20481            }
20482        }
20483
20484        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20485            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20486        }) {
20487            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20488                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20489            }
20490            self.refresh_colors(false, None, window, cx);
20491        }
20492
20493        cx.notify();
20494    }
20495
20496    pub fn set_searchable(&mut self, searchable: bool) {
20497        self.searchable = searchable;
20498    }
20499
20500    pub fn searchable(&self) -> bool {
20501        self.searchable
20502    }
20503
20504    fn open_proposed_changes_editor(
20505        &mut self,
20506        _: &OpenProposedChangesEditor,
20507        window: &mut Window,
20508        cx: &mut Context<Self>,
20509    ) {
20510        let Some(workspace) = self.workspace() else {
20511            cx.propagate();
20512            return;
20513        };
20514
20515        let selections = self.selections.all::<usize>(cx);
20516        let multi_buffer = self.buffer.read(cx);
20517        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20518        let mut new_selections_by_buffer = HashMap::default();
20519        for selection in selections {
20520            for (buffer, range, _) in
20521                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20522            {
20523                let mut range = range.to_point(buffer);
20524                range.start.column = 0;
20525                range.end.column = buffer.line_len(range.end.row);
20526                new_selections_by_buffer
20527                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20528                    .or_insert(Vec::new())
20529                    .push(range)
20530            }
20531        }
20532
20533        let proposed_changes_buffers = new_selections_by_buffer
20534            .into_iter()
20535            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20536            .collect::<Vec<_>>();
20537        let proposed_changes_editor = cx.new(|cx| {
20538            ProposedChangesEditor::new(
20539                "Proposed changes",
20540                proposed_changes_buffers,
20541                self.project.clone(),
20542                window,
20543                cx,
20544            )
20545        });
20546
20547        window.defer(cx, move |window, cx| {
20548            workspace.update(cx, |workspace, cx| {
20549                workspace.active_pane().update(cx, |pane, cx| {
20550                    pane.add_item(
20551                        Box::new(proposed_changes_editor),
20552                        true,
20553                        true,
20554                        None,
20555                        window,
20556                        cx,
20557                    );
20558                });
20559            });
20560        });
20561    }
20562
20563    pub fn open_excerpts_in_split(
20564        &mut self,
20565        _: &OpenExcerptsSplit,
20566        window: &mut Window,
20567        cx: &mut Context<Self>,
20568    ) {
20569        self.open_excerpts_common(None, true, window, cx)
20570    }
20571
20572    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20573        self.open_excerpts_common(None, false, window, cx)
20574    }
20575
20576    fn open_excerpts_common(
20577        &mut self,
20578        jump_data: Option<JumpData>,
20579        split: bool,
20580        window: &mut Window,
20581        cx: &mut Context<Self>,
20582    ) {
20583        let Some(workspace) = self.workspace() else {
20584            cx.propagate();
20585            return;
20586        };
20587
20588        if self.buffer.read(cx).is_singleton() {
20589            cx.propagate();
20590            return;
20591        }
20592
20593        let mut new_selections_by_buffer = HashMap::default();
20594        match &jump_data {
20595            Some(JumpData::MultiBufferPoint {
20596                excerpt_id,
20597                position,
20598                anchor,
20599                line_offset_from_top,
20600            }) => {
20601                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20602                if let Some(buffer) = multi_buffer_snapshot
20603                    .buffer_id_for_excerpt(*excerpt_id)
20604                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20605                {
20606                    let buffer_snapshot = buffer.read(cx).snapshot();
20607                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20608                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20609                    } else {
20610                        buffer_snapshot.clip_point(*position, Bias::Left)
20611                    };
20612                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20613                    new_selections_by_buffer.insert(
20614                        buffer,
20615                        (
20616                            vec![jump_to_offset..jump_to_offset],
20617                            Some(*line_offset_from_top),
20618                        ),
20619                    );
20620                }
20621            }
20622            Some(JumpData::MultiBufferRow {
20623                row,
20624                line_offset_from_top,
20625            }) => {
20626                let point = MultiBufferPoint::new(row.0, 0);
20627                if let Some((buffer, buffer_point, _)) =
20628                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20629                {
20630                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20631                    new_selections_by_buffer
20632                        .entry(buffer)
20633                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20634                        .0
20635                        .push(buffer_offset..buffer_offset)
20636                }
20637            }
20638            None => {
20639                let selections = self.selections.all::<usize>(cx);
20640                let multi_buffer = self.buffer.read(cx);
20641                for selection in selections {
20642                    for (snapshot, range, _, anchor) in multi_buffer
20643                        .snapshot(cx)
20644                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20645                    {
20646                        if let Some(anchor) = anchor {
20647                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20648                            else {
20649                                continue;
20650                            };
20651                            let offset = text::ToOffset::to_offset(
20652                                &anchor.text_anchor,
20653                                &buffer_handle.read(cx).snapshot(),
20654                            );
20655                            let range = offset..offset;
20656                            new_selections_by_buffer
20657                                .entry(buffer_handle)
20658                                .or_insert((Vec::new(), None))
20659                                .0
20660                                .push(range)
20661                        } else {
20662                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20663                            else {
20664                                continue;
20665                            };
20666                            new_selections_by_buffer
20667                                .entry(buffer_handle)
20668                                .or_insert((Vec::new(), None))
20669                                .0
20670                                .push(range)
20671                        }
20672                    }
20673                }
20674            }
20675        }
20676
20677        new_selections_by_buffer
20678            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20679
20680        if new_selections_by_buffer.is_empty() {
20681            return;
20682        }
20683
20684        // We defer the pane interaction because we ourselves are a workspace item
20685        // and activating a new item causes the pane to call a method on us reentrantly,
20686        // which panics if we're on the stack.
20687        window.defer(cx, move |window, cx| {
20688            workspace.update(cx, |workspace, cx| {
20689                let pane = if split {
20690                    workspace.adjacent_pane(window, cx)
20691                } else {
20692                    workspace.active_pane().clone()
20693                };
20694
20695                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20696                    let editor = buffer
20697                        .read(cx)
20698                        .file()
20699                        .is_none()
20700                        .then(|| {
20701                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20702                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20703                            // Instead, we try to activate the existing editor in the pane first.
20704                            let (editor, pane_item_index) =
20705                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20706                                    let editor = item.downcast::<Editor>()?;
20707                                    let singleton_buffer =
20708                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20709                                    if singleton_buffer == buffer {
20710                                        Some((editor, i))
20711                                    } else {
20712                                        None
20713                                    }
20714                                })?;
20715                            pane.update(cx, |pane, cx| {
20716                                pane.activate_item(pane_item_index, true, true, window, cx)
20717                            });
20718                            Some(editor)
20719                        })
20720                        .flatten()
20721                        .unwrap_or_else(|| {
20722                            workspace.open_project_item::<Self>(
20723                                pane.clone(),
20724                                buffer,
20725                                true,
20726                                true,
20727                                window,
20728                                cx,
20729                            )
20730                        });
20731
20732                    editor.update(cx, |editor, cx| {
20733                        let autoscroll = match scroll_offset {
20734                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20735                            None => Autoscroll::newest(),
20736                        };
20737                        let nav_history = editor.nav_history.take();
20738                        editor.change_selections(
20739                            SelectionEffects::scroll(autoscroll),
20740                            window,
20741                            cx,
20742                            |s| {
20743                                s.select_ranges(ranges);
20744                            },
20745                        );
20746                        editor.nav_history = nav_history;
20747                    });
20748                }
20749            })
20750        });
20751    }
20752
20753    // For now, don't allow opening excerpts in buffers that aren't backed by
20754    // regular project files.
20755    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20756        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20757    }
20758
20759    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20760        let snapshot = self.buffer.read(cx).read(cx);
20761        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20762        Some(
20763            ranges
20764                .iter()
20765                .map(move |range| {
20766                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20767                })
20768                .collect(),
20769        )
20770    }
20771
20772    fn selection_replacement_ranges(
20773        &self,
20774        range: Range<OffsetUtf16>,
20775        cx: &mut App,
20776    ) -> Vec<Range<OffsetUtf16>> {
20777        let selections = self.selections.all::<OffsetUtf16>(cx);
20778        let newest_selection = selections
20779            .iter()
20780            .max_by_key(|selection| selection.id)
20781            .unwrap();
20782        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20783        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20784        let snapshot = self.buffer.read(cx).read(cx);
20785        selections
20786            .into_iter()
20787            .map(|mut selection| {
20788                selection.start.0 =
20789                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20790                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20791                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20792                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20793            })
20794            .collect()
20795    }
20796
20797    fn report_editor_event(
20798        &self,
20799        reported_event: ReportEditorEvent,
20800        file_extension: Option<String>,
20801        cx: &App,
20802    ) {
20803        if cfg!(any(test, feature = "test-support")) {
20804            return;
20805        }
20806
20807        let Some(project) = &self.project else { return };
20808
20809        // If None, we are in a file without an extension
20810        let file = self
20811            .buffer
20812            .read(cx)
20813            .as_singleton()
20814            .and_then(|b| b.read(cx).file());
20815        let file_extension = file_extension.or(file
20816            .as_ref()
20817            .and_then(|file| Path::new(file.file_name(cx)).extension())
20818            .and_then(|e| e.to_str())
20819            .map(|a| a.to_string()));
20820
20821        let vim_mode = vim_enabled(cx);
20822
20823        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20824        let copilot_enabled = edit_predictions_provider
20825            == language::language_settings::EditPredictionProvider::Copilot;
20826        let copilot_enabled_for_language = self
20827            .buffer
20828            .read(cx)
20829            .language_settings(cx)
20830            .show_edit_predictions;
20831
20832        let project = project.read(cx);
20833        let event_type = reported_event.event_type();
20834
20835        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20836            telemetry::event!(
20837                event_type,
20838                type = if auto_saved {"autosave"} else {"manual"},
20839                file_extension,
20840                vim_mode,
20841                copilot_enabled,
20842                copilot_enabled_for_language,
20843                edit_predictions_provider,
20844                is_via_ssh = project.is_via_remote_server(),
20845            );
20846        } else {
20847            telemetry::event!(
20848                event_type,
20849                file_extension,
20850                vim_mode,
20851                copilot_enabled,
20852                copilot_enabled_for_language,
20853                edit_predictions_provider,
20854                is_via_ssh = project.is_via_remote_server(),
20855            );
20856        };
20857    }
20858
20859    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20860    /// with each line being an array of {text, highlight} objects.
20861    fn copy_highlight_json(
20862        &mut self,
20863        _: &CopyHighlightJson,
20864        window: &mut Window,
20865        cx: &mut Context<Self>,
20866    ) {
20867        #[derive(Serialize)]
20868        struct Chunk<'a> {
20869            text: String,
20870            highlight: Option<&'a str>,
20871        }
20872
20873        let snapshot = self.buffer.read(cx).snapshot(cx);
20874        let range = self
20875            .selected_text_range(false, window, cx)
20876            .and_then(|selection| {
20877                if selection.range.is_empty() {
20878                    None
20879                } else {
20880                    Some(selection.range)
20881                }
20882            })
20883            .unwrap_or_else(|| 0..snapshot.len());
20884
20885        let chunks = snapshot.chunks(range, true);
20886        let mut lines = Vec::new();
20887        let mut line: VecDeque<Chunk> = VecDeque::new();
20888
20889        let Some(style) = self.style.as_ref() else {
20890            return;
20891        };
20892
20893        for chunk in chunks {
20894            let highlight = chunk
20895                .syntax_highlight_id
20896                .and_then(|id| id.name(&style.syntax));
20897            let mut chunk_lines = chunk.text.split('\n').peekable();
20898            while let Some(text) = chunk_lines.next() {
20899                let mut merged_with_last_token = false;
20900                if let Some(last_token) = line.back_mut()
20901                    && last_token.highlight == highlight
20902                {
20903                    last_token.text.push_str(text);
20904                    merged_with_last_token = true;
20905                }
20906
20907                if !merged_with_last_token {
20908                    line.push_back(Chunk {
20909                        text: text.into(),
20910                        highlight,
20911                    });
20912                }
20913
20914                if chunk_lines.peek().is_some() {
20915                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20916                        line.pop_front();
20917                    }
20918                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20919                        line.pop_back();
20920                    }
20921
20922                    lines.push(mem::take(&mut line));
20923                }
20924            }
20925        }
20926
20927        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20928            return;
20929        };
20930        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20931    }
20932
20933    pub fn open_context_menu(
20934        &mut self,
20935        _: &OpenContextMenu,
20936        window: &mut Window,
20937        cx: &mut Context<Self>,
20938    ) {
20939        self.request_autoscroll(Autoscroll::newest(), cx);
20940        let position = self.selections.newest_display(cx).start;
20941        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20942    }
20943
20944    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20945        &self.inlay_hint_cache
20946    }
20947
20948    pub fn replay_insert_event(
20949        &mut self,
20950        text: &str,
20951        relative_utf16_range: Option<Range<isize>>,
20952        window: &mut Window,
20953        cx: &mut Context<Self>,
20954    ) {
20955        if !self.input_enabled {
20956            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20957            return;
20958        }
20959        if let Some(relative_utf16_range) = relative_utf16_range {
20960            let selections = self.selections.all::<OffsetUtf16>(cx);
20961            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20962                let new_ranges = selections.into_iter().map(|range| {
20963                    let start = OffsetUtf16(
20964                        range
20965                            .head()
20966                            .0
20967                            .saturating_add_signed(relative_utf16_range.start),
20968                    );
20969                    let end = OffsetUtf16(
20970                        range
20971                            .head()
20972                            .0
20973                            .saturating_add_signed(relative_utf16_range.end),
20974                    );
20975                    start..end
20976                });
20977                s.select_ranges(new_ranges);
20978            });
20979        }
20980
20981        self.handle_input(text, window, cx);
20982    }
20983
20984    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20985        let Some(provider) = self.semantics_provider.as_ref() else {
20986            return false;
20987        };
20988
20989        let mut supports = false;
20990        self.buffer().update(cx, |this, cx| {
20991            this.for_each_buffer(|buffer| {
20992                supports |= provider.supports_inlay_hints(buffer, cx);
20993            });
20994        });
20995
20996        supports
20997    }
20998
20999    pub fn is_focused(&self, window: &Window) -> bool {
21000        self.focus_handle.is_focused(window)
21001    }
21002
21003    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21004        cx.emit(EditorEvent::Focused);
21005
21006        if let Some(descendant) = self
21007            .last_focused_descendant
21008            .take()
21009            .and_then(|descendant| descendant.upgrade())
21010        {
21011            window.focus(&descendant);
21012        } else {
21013            if let Some(blame) = self.blame.as_ref() {
21014                blame.update(cx, GitBlame::focus)
21015            }
21016
21017            self.blink_manager.update(cx, BlinkManager::enable);
21018            self.show_cursor_names(window, cx);
21019            self.buffer.update(cx, |buffer, cx| {
21020                buffer.finalize_last_transaction(cx);
21021                if self.leader_id.is_none() {
21022                    buffer.set_active_selections(
21023                        &self.selections.disjoint_anchors(),
21024                        self.selections.line_mode,
21025                        self.cursor_shape,
21026                        cx,
21027                    );
21028                }
21029            });
21030        }
21031    }
21032
21033    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21034        cx.emit(EditorEvent::FocusedIn)
21035    }
21036
21037    fn handle_focus_out(
21038        &mut self,
21039        event: FocusOutEvent,
21040        _window: &mut Window,
21041        cx: &mut Context<Self>,
21042    ) {
21043        if event.blurred != self.focus_handle {
21044            self.last_focused_descendant = Some(event.blurred);
21045        }
21046        self.selection_drag_state = SelectionDragState::None;
21047        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21048    }
21049
21050    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21051        self.blink_manager.update(cx, BlinkManager::disable);
21052        self.buffer
21053            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21054
21055        if let Some(blame) = self.blame.as_ref() {
21056            blame.update(cx, GitBlame::blur)
21057        }
21058        if !self.hover_state.focused(window, cx) {
21059            hide_hover(self, cx);
21060        }
21061        if !self
21062            .context_menu
21063            .borrow()
21064            .as_ref()
21065            .is_some_and(|context_menu| context_menu.focused(window, cx))
21066        {
21067            self.hide_context_menu(window, cx);
21068        }
21069        self.discard_edit_prediction(false, cx);
21070        cx.emit(EditorEvent::Blurred);
21071        cx.notify();
21072    }
21073
21074    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21075        let mut pending: String = window
21076            .pending_input_keystrokes()
21077            .into_iter()
21078            .flatten()
21079            .filter_map(|keystroke| {
21080                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21081                    keystroke.key_char.clone()
21082                } else {
21083                    None
21084                }
21085            })
21086            .collect();
21087
21088        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21089            pending = "".to_string();
21090        }
21091
21092        let existing_pending = self
21093            .text_highlights::<PendingInput>(cx)
21094            .map(|(_, ranges)| ranges.to_vec());
21095        if existing_pending.is_none() && pending.is_empty() {
21096            return;
21097        }
21098        let transaction =
21099            self.transact(window, cx, |this, window, cx| {
21100                let selections = this.selections.all::<usize>(cx);
21101                let edits = selections
21102                    .iter()
21103                    .map(|selection| (selection.end..selection.end, pending.clone()));
21104                this.edit(edits, cx);
21105                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21106                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21107                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21108                    }));
21109                });
21110                if let Some(existing_ranges) = existing_pending {
21111                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21112                    this.edit(edits, cx);
21113                }
21114            });
21115
21116        let snapshot = self.snapshot(window, cx);
21117        let ranges = self
21118            .selections
21119            .all::<usize>(cx)
21120            .into_iter()
21121            .map(|selection| {
21122                snapshot.buffer_snapshot.anchor_after(selection.end)
21123                    ..snapshot
21124                        .buffer_snapshot
21125                        .anchor_before(selection.end + pending.len())
21126            })
21127            .collect();
21128
21129        if pending.is_empty() {
21130            self.clear_highlights::<PendingInput>(cx);
21131        } else {
21132            self.highlight_text::<PendingInput>(
21133                ranges,
21134                HighlightStyle {
21135                    underline: Some(UnderlineStyle {
21136                        thickness: px(1.),
21137                        color: None,
21138                        wavy: false,
21139                    }),
21140                    ..Default::default()
21141                },
21142                cx,
21143            );
21144        }
21145
21146        self.ime_transaction = self.ime_transaction.or(transaction);
21147        if let Some(transaction) = self.ime_transaction {
21148            self.buffer.update(cx, |buffer, cx| {
21149                buffer.group_until_transaction(transaction, cx);
21150            });
21151        }
21152
21153        if self.text_highlights::<PendingInput>(cx).is_none() {
21154            self.ime_transaction.take();
21155        }
21156    }
21157
21158    pub fn register_action_renderer(
21159        &mut self,
21160        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21161    ) -> Subscription {
21162        let id = self.next_editor_action_id.post_inc();
21163        self.editor_actions
21164            .borrow_mut()
21165            .insert(id, Box::new(listener));
21166
21167        let editor_actions = self.editor_actions.clone();
21168        Subscription::new(move || {
21169            editor_actions.borrow_mut().remove(&id);
21170        })
21171    }
21172
21173    pub fn register_action<A: Action>(
21174        &mut self,
21175        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21176    ) -> Subscription {
21177        let id = self.next_editor_action_id.post_inc();
21178        let listener = Arc::new(listener);
21179        self.editor_actions.borrow_mut().insert(
21180            id,
21181            Box::new(move |_, window, _| {
21182                let listener = listener.clone();
21183                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21184                    let action = action.downcast_ref().unwrap();
21185                    if phase == DispatchPhase::Bubble {
21186                        listener(action, window, cx)
21187                    }
21188                })
21189            }),
21190        );
21191
21192        let editor_actions = self.editor_actions.clone();
21193        Subscription::new(move || {
21194            editor_actions.borrow_mut().remove(&id);
21195        })
21196    }
21197
21198    pub fn file_header_size(&self) -> u32 {
21199        FILE_HEADER_HEIGHT
21200    }
21201
21202    pub fn restore(
21203        &mut self,
21204        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21205        window: &mut Window,
21206        cx: &mut Context<Self>,
21207    ) {
21208        let workspace = self.workspace();
21209        let project = self.project();
21210        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21211            let mut tasks = Vec::new();
21212            for (buffer_id, changes) in revert_changes {
21213                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21214                    buffer.update(cx, |buffer, cx| {
21215                        buffer.edit(
21216                            changes
21217                                .into_iter()
21218                                .map(|(range, text)| (range, text.to_string())),
21219                            None,
21220                            cx,
21221                        );
21222                    });
21223
21224                    if let Some(project) =
21225                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21226                    {
21227                        project.update(cx, |project, cx| {
21228                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21229                        })
21230                    }
21231                }
21232            }
21233            tasks
21234        });
21235        cx.spawn_in(window, async move |_, cx| {
21236            for (buffer, task) in save_tasks {
21237                let result = task.await;
21238                if result.is_err() {
21239                    let Some(path) = buffer
21240                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21241                        .ok()
21242                    else {
21243                        continue;
21244                    };
21245                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21246                        let Some(task) = cx
21247                            .update_window_entity(workspace, |workspace, window, cx| {
21248                                workspace
21249                                    .open_path_preview(path, None, false, false, false, window, cx)
21250                            })
21251                            .ok()
21252                        else {
21253                            continue;
21254                        };
21255                        task.await.log_err();
21256                    }
21257                }
21258            }
21259        })
21260        .detach();
21261        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21262            selections.refresh()
21263        });
21264    }
21265
21266    pub fn to_pixel_point(
21267        &self,
21268        source: multi_buffer::Anchor,
21269        editor_snapshot: &EditorSnapshot,
21270        window: &mut Window,
21271    ) -> Option<gpui::Point<Pixels>> {
21272        let source_point = source.to_display_point(editor_snapshot);
21273        self.display_to_pixel_point(source_point, editor_snapshot, window)
21274    }
21275
21276    pub fn display_to_pixel_point(
21277        &self,
21278        source: DisplayPoint,
21279        editor_snapshot: &EditorSnapshot,
21280        window: &mut Window,
21281    ) -> Option<gpui::Point<Pixels>> {
21282        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21283        let text_layout_details = self.text_layout_details(window);
21284        let scroll_top = text_layout_details
21285            .scroll_anchor
21286            .scroll_position(editor_snapshot)
21287            .y;
21288
21289        if source.row().as_f32() < scroll_top.floor() {
21290            return None;
21291        }
21292        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21293        let source_y = line_height * (source.row().as_f32() - scroll_top);
21294        Some(gpui::Point::new(source_x, source_y))
21295    }
21296
21297    pub fn has_visible_completions_menu(&self) -> bool {
21298        !self.edit_prediction_preview_is_active()
21299            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21300                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21301            })
21302    }
21303
21304    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21305        if self.mode.is_minimap() {
21306            return;
21307        }
21308        self.addons
21309            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21310    }
21311
21312    pub fn unregister_addon<T: Addon>(&mut self) {
21313        self.addons.remove(&std::any::TypeId::of::<T>());
21314    }
21315
21316    pub fn addon<T: Addon>(&self) -> Option<&T> {
21317        let type_id = std::any::TypeId::of::<T>();
21318        self.addons
21319            .get(&type_id)
21320            .and_then(|item| item.to_any().downcast_ref::<T>())
21321    }
21322
21323    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21324        let type_id = std::any::TypeId::of::<T>();
21325        self.addons
21326            .get_mut(&type_id)
21327            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21328    }
21329
21330    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21331        let text_layout_details = self.text_layout_details(window);
21332        let style = &text_layout_details.editor_style;
21333        let font_id = window.text_system().resolve_font(&style.text.font());
21334        let font_size = style.text.font_size.to_pixels(window.rem_size());
21335        let line_height = style.text.line_height_in_pixels(window.rem_size());
21336        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21337        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21338
21339        CharacterDimensions {
21340            em_width,
21341            em_advance,
21342            line_height,
21343        }
21344    }
21345
21346    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21347        self.load_diff_task.clone()
21348    }
21349
21350    fn read_metadata_from_db(
21351        &mut self,
21352        item_id: u64,
21353        workspace_id: WorkspaceId,
21354        window: &mut Window,
21355        cx: &mut Context<Editor>,
21356    ) {
21357        if self.is_singleton(cx)
21358            && !self.mode.is_minimap()
21359            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21360        {
21361            let buffer_snapshot = OnceCell::new();
21362
21363            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21364                && !folds.is_empty()
21365            {
21366                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21367                self.fold_ranges(
21368                    folds
21369                        .into_iter()
21370                        .map(|(start, end)| {
21371                            snapshot.clip_offset(start, Bias::Left)
21372                                ..snapshot.clip_offset(end, Bias::Right)
21373                        })
21374                        .collect(),
21375                    false,
21376                    window,
21377                    cx,
21378                );
21379            }
21380
21381            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21382                && !selections.is_empty()
21383            {
21384                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21385                // skip adding the initial selection to selection history
21386                self.selection_history.mode = SelectionHistoryMode::Skipping;
21387                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21388                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21389                        snapshot.clip_offset(start, Bias::Left)
21390                            ..snapshot.clip_offset(end, Bias::Right)
21391                    }));
21392                });
21393                self.selection_history.mode = SelectionHistoryMode::Normal;
21394            };
21395        }
21396
21397        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21398    }
21399
21400    fn update_lsp_data(
21401        &mut self,
21402        ignore_cache: bool,
21403        for_buffer: Option<BufferId>,
21404        window: &mut Window,
21405        cx: &mut Context<'_, Self>,
21406    ) {
21407        self.pull_diagnostics(for_buffer, window, cx);
21408        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21409    }
21410}
21411
21412fn vim_enabled(cx: &App) -> bool {
21413    cx.global::<SettingsStore>()
21414        .raw_user_settings()
21415        .get("vim_mode")
21416        == Some(&serde_json::Value::Bool(true))
21417}
21418
21419fn process_completion_for_edit(
21420    completion: &Completion,
21421    intent: CompletionIntent,
21422    buffer: &Entity<Buffer>,
21423    cursor_position: &text::Anchor,
21424    cx: &mut Context<Editor>,
21425) -> CompletionEdit {
21426    let buffer = buffer.read(cx);
21427    let buffer_snapshot = buffer.snapshot();
21428    let (snippet, new_text) = if completion.is_snippet() {
21429        // Workaround for typescript language server issues so that methods don't expand within
21430        // strings and functions with type expressions. The previous point is used because the query
21431        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21432        let mut snippet_source = completion.new_text.clone();
21433        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21434        previous_point.column = previous_point.column.saturating_sub(1);
21435        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21436            && scope.prefers_label_for_snippet_in_completion()
21437            && let Some(label) = completion.label()
21438            && matches!(
21439                completion.kind(),
21440                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21441            )
21442        {
21443            snippet_source = label;
21444        }
21445        match Snippet::parse(&snippet_source).log_err() {
21446            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21447            None => (None, completion.new_text.clone()),
21448        }
21449    } else {
21450        (None, completion.new_text.clone())
21451    };
21452
21453    let mut range_to_replace = {
21454        let replace_range = &completion.replace_range;
21455        if let CompletionSource::Lsp {
21456            insert_range: Some(insert_range),
21457            ..
21458        } = &completion.source
21459        {
21460            debug_assert_eq!(
21461                insert_range.start, replace_range.start,
21462                "insert_range and replace_range should start at the same position"
21463            );
21464            debug_assert!(
21465                insert_range
21466                    .start
21467                    .cmp(cursor_position, &buffer_snapshot)
21468                    .is_le(),
21469                "insert_range should start before or at cursor position"
21470            );
21471            debug_assert!(
21472                replace_range
21473                    .start
21474                    .cmp(cursor_position, &buffer_snapshot)
21475                    .is_le(),
21476                "replace_range should start before or at cursor position"
21477            );
21478
21479            let should_replace = match intent {
21480                CompletionIntent::CompleteWithInsert => false,
21481                CompletionIntent::CompleteWithReplace => true,
21482                CompletionIntent::Complete | CompletionIntent::Compose => {
21483                    let insert_mode =
21484                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21485                            .completions
21486                            .lsp_insert_mode;
21487                    match insert_mode {
21488                        LspInsertMode::Insert => false,
21489                        LspInsertMode::Replace => true,
21490                        LspInsertMode::ReplaceSubsequence => {
21491                            let mut text_to_replace = buffer.chars_for_range(
21492                                buffer.anchor_before(replace_range.start)
21493                                    ..buffer.anchor_after(replace_range.end),
21494                            );
21495                            let mut current_needle = text_to_replace.next();
21496                            for haystack_ch in completion.label.text.chars() {
21497                                if let Some(needle_ch) = current_needle
21498                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21499                                {
21500                                    current_needle = text_to_replace.next();
21501                                }
21502                            }
21503                            current_needle.is_none()
21504                        }
21505                        LspInsertMode::ReplaceSuffix => {
21506                            if replace_range
21507                                .end
21508                                .cmp(cursor_position, &buffer_snapshot)
21509                                .is_gt()
21510                            {
21511                                let range_after_cursor = *cursor_position..replace_range.end;
21512                                let text_after_cursor = buffer
21513                                    .text_for_range(
21514                                        buffer.anchor_before(range_after_cursor.start)
21515                                            ..buffer.anchor_after(range_after_cursor.end),
21516                                    )
21517                                    .collect::<String>()
21518                                    .to_ascii_lowercase();
21519                                completion
21520                                    .label
21521                                    .text
21522                                    .to_ascii_lowercase()
21523                                    .ends_with(&text_after_cursor)
21524                            } else {
21525                                true
21526                            }
21527                        }
21528                    }
21529                }
21530            };
21531
21532            if should_replace {
21533                replace_range.clone()
21534            } else {
21535                insert_range.clone()
21536            }
21537        } else {
21538            replace_range.clone()
21539        }
21540    };
21541
21542    if range_to_replace
21543        .end
21544        .cmp(cursor_position, &buffer_snapshot)
21545        .is_lt()
21546    {
21547        range_to_replace.end = *cursor_position;
21548    }
21549
21550    CompletionEdit {
21551        new_text,
21552        replace_range: range_to_replace.to_offset(buffer),
21553        snippet,
21554    }
21555}
21556
21557struct CompletionEdit {
21558    new_text: String,
21559    replace_range: Range<usize>,
21560    snippet: Option<Snippet>,
21561}
21562
21563fn insert_extra_newline_brackets(
21564    buffer: &MultiBufferSnapshot,
21565    range: Range<usize>,
21566    language: &language::LanguageScope,
21567) -> bool {
21568    let leading_whitespace_len = buffer
21569        .reversed_chars_at(range.start)
21570        .take_while(|c| c.is_whitespace() && *c != '\n')
21571        .map(|c| c.len_utf8())
21572        .sum::<usize>();
21573    let trailing_whitespace_len = buffer
21574        .chars_at(range.end)
21575        .take_while(|c| c.is_whitespace() && *c != '\n')
21576        .map(|c| c.len_utf8())
21577        .sum::<usize>();
21578    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21579
21580    language.brackets().any(|(pair, enabled)| {
21581        let pair_start = pair.start.trim_end();
21582        let pair_end = pair.end.trim_start();
21583
21584        enabled
21585            && pair.newline
21586            && buffer.contains_str_at(range.end, pair_end)
21587            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21588    })
21589}
21590
21591fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21592    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21593        [(buffer, range, _)] => (*buffer, range.clone()),
21594        _ => return false,
21595    };
21596    let pair = {
21597        let mut result: Option<BracketMatch> = None;
21598
21599        for pair in buffer
21600            .all_bracket_ranges(range.clone())
21601            .filter(move |pair| {
21602                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21603            })
21604        {
21605            let len = pair.close_range.end - pair.open_range.start;
21606
21607            if let Some(existing) = &result {
21608                let existing_len = existing.close_range.end - existing.open_range.start;
21609                if len > existing_len {
21610                    continue;
21611                }
21612            }
21613
21614            result = Some(pair);
21615        }
21616
21617        result
21618    };
21619    let Some(pair) = pair else {
21620        return false;
21621    };
21622    pair.newline_only
21623        && buffer
21624            .chars_for_range(pair.open_range.end..range.start)
21625            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21626            .all(|c| c.is_whitespace() && c != '\n')
21627}
21628
21629fn update_uncommitted_diff_for_buffer(
21630    editor: Entity<Editor>,
21631    project: &Entity<Project>,
21632    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21633    buffer: Entity<MultiBuffer>,
21634    cx: &mut App,
21635) -> Task<()> {
21636    let mut tasks = Vec::new();
21637    project.update(cx, |project, cx| {
21638        for buffer in buffers {
21639            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21640                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21641            }
21642        }
21643    });
21644    cx.spawn(async move |cx| {
21645        let diffs = future::join_all(tasks).await;
21646        if editor
21647            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21648            .unwrap_or(false)
21649        {
21650            return;
21651        }
21652
21653        buffer
21654            .update(cx, |buffer, cx| {
21655                for diff in diffs.into_iter().flatten() {
21656                    buffer.add_diff(diff, cx);
21657                }
21658            })
21659            .ok();
21660    })
21661}
21662
21663fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21664    let tab_size = tab_size.get() as usize;
21665    let mut width = offset;
21666
21667    for ch in text.chars() {
21668        width += if ch == '\t' {
21669            tab_size - (width % tab_size)
21670        } else {
21671            1
21672        };
21673    }
21674
21675    width - offset
21676}
21677
21678#[cfg(test)]
21679mod tests {
21680    use super::*;
21681
21682    #[test]
21683    fn test_string_size_with_expanded_tabs() {
21684        let nz = |val| NonZeroU32::new(val).unwrap();
21685        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21686        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21687        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21688        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21689        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21690        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21691        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21692        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21693    }
21694}
21695
21696/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21697struct WordBreakingTokenizer<'a> {
21698    input: &'a str,
21699}
21700
21701impl<'a> WordBreakingTokenizer<'a> {
21702    fn new(input: &'a str) -> Self {
21703        Self { input }
21704    }
21705}
21706
21707fn is_char_ideographic(ch: char) -> bool {
21708    use unicode_script::Script::*;
21709    use unicode_script::UnicodeScript;
21710    matches!(ch.script(), Han | Tangut | Yi)
21711}
21712
21713fn is_grapheme_ideographic(text: &str) -> bool {
21714    text.chars().any(is_char_ideographic)
21715}
21716
21717fn is_grapheme_whitespace(text: &str) -> bool {
21718    text.chars().any(|x| x.is_whitespace())
21719}
21720
21721fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21722    text.chars()
21723        .next()
21724        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21725}
21726
21727#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21728enum WordBreakToken<'a> {
21729    Word { token: &'a str, grapheme_len: usize },
21730    InlineWhitespace { token: &'a str, grapheme_len: usize },
21731    Newline,
21732}
21733
21734impl<'a> Iterator for WordBreakingTokenizer<'a> {
21735    /// Yields a span, the count of graphemes in the token, and whether it was
21736    /// whitespace. Note that it also breaks at word boundaries.
21737    type Item = WordBreakToken<'a>;
21738
21739    fn next(&mut self) -> Option<Self::Item> {
21740        use unicode_segmentation::UnicodeSegmentation;
21741        if self.input.is_empty() {
21742            return None;
21743        }
21744
21745        let mut iter = self.input.graphemes(true).peekable();
21746        let mut offset = 0;
21747        let mut grapheme_len = 0;
21748        if let Some(first_grapheme) = iter.next() {
21749            let is_newline = first_grapheme == "\n";
21750            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21751            offset += first_grapheme.len();
21752            grapheme_len += 1;
21753            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21754                if let Some(grapheme) = iter.peek().copied()
21755                    && should_stay_with_preceding_ideograph(grapheme)
21756                {
21757                    offset += grapheme.len();
21758                    grapheme_len += 1;
21759                }
21760            } else {
21761                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21762                let mut next_word_bound = words.peek().copied();
21763                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21764                    next_word_bound = words.next();
21765                }
21766                while let Some(grapheme) = iter.peek().copied() {
21767                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21768                        break;
21769                    };
21770                    if is_grapheme_whitespace(grapheme) != is_whitespace
21771                        || (grapheme == "\n") != is_newline
21772                    {
21773                        break;
21774                    };
21775                    offset += grapheme.len();
21776                    grapheme_len += 1;
21777                    iter.next();
21778                }
21779            }
21780            let token = &self.input[..offset];
21781            self.input = &self.input[offset..];
21782            if token == "\n" {
21783                Some(WordBreakToken::Newline)
21784            } else if is_whitespace {
21785                Some(WordBreakToken::InlineWhitespace {
21786                    token,
21787                    grapheme_len,
21788                })
21789            } else {
21790                Some(WordBreakToken::Word {
21791                    token,
21792                    grapheme_len,
21793                })
21794            }
21795        } else {
21796            None
21797        }
21798    }
21799}
21800
21801#[test]
21802fn test_word_breaking_tokenizer() {
21803    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21804        ("", &[]),
21805        ("  ", &[whitespace("  ", 2)]),
21806        ("Ʒ", &[word("Ʒ", 1)]),
21807        ("Ǽ", &[word("Ǽ", 1)]),
21808        ("", &[word("", 1)]),
21809        ("⋑⋑", &[word("⋑⋑", 2)]),
21810        (
21811            "原理,进而",
21812            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21813        ),
21814        (
21815            "hello world",
21816            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21817        ),
21818        (
21819            "hello, world",
21820            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21821        ),
21822        (
21823            "  hello world",
21824            &[
21825                whitespace("  ", 2),
21826                word("hello", 5),
21827                whitespace(" ", 1),
21828                word("world", 5),
21829            ],
21830        ),
21831        (
21832            "这是什么 \n 钢笔",
21833            &[
21834                word("", 1),
21835                word("", 1),
21836                word("", 1),
21837                word("", 1),
21838                whitespace(" ", 1),
21839                newline(),
21840                whitespace(" ", 1),
21841                word("", 1),
21842                word("", 1),
21843            ],
21844        ),
21845        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21846    ];
21847
21848    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21849        WordBreakToken::Word {
21850            token,
21851            grapheme_len,
21852        }
21853    }
21854
21855    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21856        WordBreakToken::InlineWhitespace {
21857            token,
21858            grapheme_len,
21859        }
21860    }
21861
21862    fn newline() -> WordBreakToken<'static> {
21863        WordBreakToken::Newline
21864    }
21865
21866    for (input, result) in tests {
21867        assert_eq!(
21868            WordBreakingTokenizer::new(input)
21869                .collect::<Vec<_>>()
21870                .as_slice(),
21871            *result,
21872        );
21873    }
21874}
21875
21876fn wrap_with_prefix(
21877    first_line_prefix: String,
21878    subsequent_lines_prefix: String,
21879    unwrapped_text: String,
21880    wrap_column: usize,
21881    tab_size: NonZeroU32,
21882    preserve_existing_whitespace: bool,
21883) -> String {
21884    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21885    let subsequent_lines_prefix_len =
21886        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21887    let mut wrapped_text = String::new();
21888    let mut current_line = first_line_prefix;
21889    let mut is_first_line = true;
21890
21891    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21892    let mut current_line_len = first_line_prefix_len;
21893    let mut in_whitespace = false;
21894    for token in tokenizer {
21895        let have_preceding_whitespace = in_whitespace;
21896        match token {
21897            WordBreakToken::Word {
21898                token,
21899                grapheme_len,
21900            } => {
21901                in_whitespace = false;
21902                let current_prefix_len = if is_first_line {
21903                    first_line_prefix_len
21904                } else {
21905                    subsequent_lines_prefix_len
21906                };
21907                if current_line_len + grapheme_len > wrap_column
21908                    && current_line_len != current_prefix_len
21909                {
21910                    wrapped_text.push_str(current_line.trim_end());
21911                    wrapped_text.push('\n');
21912                    is_first_line = false;
21913                    current_line = subsequent_lines_prefix.clone();
21914                    current_line_len = subsequent_lines_prefix_len;
21915                }
21916                current_line.push_str(token);
21917                current_line_len += grapheme_len;
21918            }
21919            WordBreakToken::InlineWhitespace {
21920                mut token,
21921                mut grapheme_len,
21922            } => {
21923                in_whitespace = true;
21924                if have_preceding_whitespace && !preserve_existing_whitespace {
21925                    continue;
21926                }
21927                if !preserve_existing_whitespace {
21928                    token = " ";
21929                    grapheme_len = 1;
21930                }
21931                let current_prefix_len = if is_first_line {
21932                    first_line_prefix_len
21933                } else {
21934                    subsequent_lines_prefix_len
21935                };
21936                if current_line_len + grapheme_len > wrap_column {
21937                    wrapped_text.push_str(current_line.trim_end());
21938                    wrapped_text.push('\n');
21939                    is_first_line = false;
21940                    current_line = subsequent_lines_prefix.clone();
21941                    current_line_len = subsequent_lines_prefix_len;
21942                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21943                    current_line.push_str(token);
21944                    current_line_len += grapheme_len;
21945                }
21946            }
21947            WordBreakToken::Newline => {
21948                in_whitespace = true;
21949                let current_prefix_len = if is_first_line {
21950                    first_line_prefix_len
21951                } else {
21952                    subsequent_lines_prefix_len
21953                };
21954                if preserve_existing_whitespace {
21955                    wrapped_text.push_str(current_line.trim_end());
21956                    wrapped_text.push('\n');
21957                    is_first_line = false;
21958                    current_line = subsequent_lines_prefix.clone();
21959                    current_line_len = subsequent_lines_prefix_len;
21960                } else if have_preceding_whitespace {
21961                    continue;
21962                } else if current_line_len + 1 > wrap_column
21963                    && current_line_len != current_prefix_len
21964                {
21965                    wrapped_text.push_str(current_line.trim_end());
21966                    wrapped_text.push('\n');
21967                    is_first_line = false;
21968                    current_line = subsequent_lines_prefix.clone();
21969                    current_line_len = subsequent_lines_prefix_len;
21970                } else if current_line_len != current_prefix_len {
21971                    current_line.push(' ');
21972                    current_line_len += 1;
21973                }
21974            }
21975        }
21976    }
21977
21978    if !current_line.is_empty() {
21979        wrapped_text.push_str(&current_line);
21980    }
21981    wrapped_text
21982}
21983
21984#[test]
21985fn test_wrap_with_prefix() {
21986    assert_eq!(
21987        wrap_with_prefix(
21988            "# ".to_string(),
21989            "# ".to_string(),
21990            "abcdefg".to_string(),
21991            4,
21992            NonZeroU32::new(4).unwrap(),
21993            false,
21994        ),
21995        "# abcdefg"
21996    );
21997    assert_eq!(
21998        wrap_with_prefix(
21999            "".to_string(),
22000            "".to_string(),
22001            "\thello world".to_string(),
22002            8,
22003            NonZeroU32::new(4).unwrap(),
22004            false,
22005        ),
22006        "hello\nworld"
22007    );
22008    assert_eq!(
22009        wrap_with_prefix(
22010            "// ".to_string(),
22011            "// ".to_string(),
22012            "xx \nyy zz aa bb cc".to_string(),
22013            12,
22014            NonZeroU32::new(4).unwrap(),
22015            false,
22016        ),
22017        "// xx yy zz\n// aa bb cc"
22018    );
22019    assert_eq!(
22020        wrap_with_prefix(
22021            String::new(),
22022            String::new(),
22023            "这是什么 \n 钢笔".to_string(),
22024            3,
22025            NonZeroU32::new(4).unwrap(),
22026            false,
22027        ),
22028        "这是什\n么 钢\n"
22029    );
22030}
22031
22032pub trait CollaborationHub {
22033    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22034    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22035    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22036}
22037
22038impl CollaborationHub for Entity<Project> {
22039    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22040        self.read(cx).collaborators()
22041    }
22042
22043    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22044        self.read(cx).user_store().read(cx).participant_indices()
22045    }
22046
22047    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22048        let this = self.read(cx);
22049        let user_ids = this.collaborators().values().map(|c| c.user_id);
22050        this.user_store().read(cx).participant_names(user_ids, cx)
22051    }
22052}
22053
22054pub trait SemanticsProvider {
22055    fn hover(
22056        &self,
22057        buffer: &Entity<Buffer>,
22058        position: text::Anchor,
22059        cx: &mut App,
22060    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22061
22062    fn inline_values(
22063        &self,
22064        buffer_handle: Entity<Buffer>,
22065        range: Range<text::Anchor>,
22066        cx: &mut App,
22067    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22068
22069    fn inlay_hints(
22070        &self,
22071        buffer_handle: Entity<Buffer>,
22072        range: Range<text::Anchor>,
22073        cx: &mut App,
22074    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22075
22076    fn resolve_inlay_hint(
22077        &self,
22078        hint: InlayHint,
22079        buffer_handle: Entity<Buffer>,
22080        server_id: LanguageServerId,
22081        cx: &mut App,
22082    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22083
22084    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22085
22086    fn document_highlights(
22087        &self,
22088        buffer: &Entity<Buffer>,
22089        position: text::Anchor,
22090        cx: &mut App,
22091    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22092
22093    fn definitions(
22094        &self,
22095        buffer: &Entity<Buffer>,
22096        position: text::Anchor,
22097        kind: GotoDefinitionKind,
22098        cx: &mut App,
22099    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22100
22101    fn range_for_rename(
22102        &self,
22103        buffer: &Entity<Buffer>,
22104        position: text::Anchor,
22105        cx: &mut App,
22106    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22107
22108    fn perform_rename(
22109        &self,
22110        buffer: &Entity<Buffer>,
22111        position: text::Anchor,
22112        new_name: String,
22113        cx: &mut App,
22114    ) -> Option<Task<Result<ProjectTransaction>>>;
22115}
22116
22117pub trait CompletionProvider {
22118    fn completions(
22119        &self,
22120        excerpt_id: ExcerptId,
22121        buffer: &Entity<Buffer>,
22122        buffer_position: text::Anchor,
22123        trigger: CompletionContext,
22124        window: &mut Window,
22125        cx: &mut Context<Editor>,
22126    ) -> Task<Result<Vec<CompletionResponse>>>;
22127
22128    fn resolve_completions(
22129        &self,
22130        _buffer: Entity<Buffer>,
22131        _completion_indices: Vec<usize>,
22132        _completions: Rc<RefCell<Box<[Completion]>>>,
22133        _cx: &mut Context<Editor>,
22134    ) -> Task<Result<bool>> {
22135        Task::ready(Ok(false))
22136    }
22137
22138    fn apply_additional_edits_for_completion(
22139        &self,
22140        _buffer: Entity<Buffer>,
22141        _completions: Rc<RefCell<Box<[Completion]>>>,
22142        _completion_index: usize,
22143        _push_to_history: bool,
22144        _cx: &mut Context<Editor>,
22145    ) -> Task<Result<Option<language::Transaction>>> {
22146        Task::ready(Ok(None))
22147    }
22148
22149    fn is_completion_trigger(
22150        &self,
22151        buffer: &Entity<Buffer>,
22152        position: language::Anchor,
22153        text: &str,
22154        trigger_in_words: bool,
22155        menu_is_open: bool,
22156        cx: &mut Context<Editor>,
22157    ) -> bool;
22158
22159    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22160
22161    fn sort_completions(&self) -> bool {
22162        true
22163    }
22164
22165    fn filter_completions(&self) -> bool {
22166        true
22167    }
22168}
22169
22170pub trait CodeActionProvider {
22171    fn id(&self) -> Arc<str>;
22172
22173    fn code_actions(
22174        &self,
22175        buffer: &Entity<Buffer>,
22176        range: Range<text::Anchor>,
22177        window: &mut Window,
22178        cx: &mut App,
22179    ) -> Task<Result<Vec<CodeAction>>>;
22180
22181    fn apply_code_action(
22182        &self,
22183        buffer_handle: Entity<Buffer>,
22184        action: CodeAction,
22185        excerpt_id: ExcerptId,
22186        push_to_history: bool,
22187        window: &mut Window,
22188        cx: &mut App,
22189    ) -> Task<Result<ProjectTransaction>>;
22190}
22191
22192impl CodeActionProvider for Entity<Project> {
22193    fn id(&self) -> Arc<str> {
22194        "project".into()
22195    }
22196
22197    fn code_actions(
22198        &self,
22199        buffer: &Entity<Buffer>,
22200        range: Range<text::Anchor>,
22201        _window: &mut Window,
22202        cx: &mut App,
22203    ) -> Task<Result<Vec<CodeAction>>> {
22204        self.update(cx, |project, cx| {
22205            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22206            let code_actions = project.code_actions(buffer, range, None, cx);
22207            cx.background_spawn(async move {
22208                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22209                Ok(code_lens_actions
22210                    .context("code lens fetch")?
22211                    .into_iter()
22212                    .flatten()
22213                    .chain(
22214                        code_actions
22215                            .context("code action fetch")?
22216                            .into_iter()
22217                            .flatten(),
22218                    )
22219                    .collect())
22220            })
22221        })
22222    }
22223
22224    fn apply_code_action(
22225        &self,
22226        buffer_handle: Entity<Buffer>,
22227        action: CodeAction,
22228        _excerpt_id: ExcerptId,
22229        push_to_history: bool,
22230        _window: &mut Window,
22231        cx: &mut App,
22232    ) -> Task<Result<ProjectTransaction>> {
22233        self.update(cx, |project, cx| {
22234            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22235        })
22236    }
22237}
22238
22239fn snippet_completions(
22240    project: &Project,
22241    buffer: &Entity<Buffer>,
22242    buffer_position: text::Anchor,
22243    cx: &mut App,
22244) -> Task<Result<CompletionResponse>> {
22245    let languages = buffer.read(cx).languages_at(buffer_position);
22246    let snippet_store = project.snippets().read(cx);
22247
22248    let scopes: Vec<_> = languages
22249        .iter()
22250        .filter_map(|language| {
22251            let language_name = language.lsp_id();
22252            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22253
22254            if snippets.is_empty() {
22255                None
22256            } else {
22257                Some((language.default_scope(), snippets))
22258            }
22259        })
22260        .collect();
22261
22262    if scopes.is_empty() {
22263        return Task::ready(Ok(CompletionResponse {
22264            completions: vec![],
22265            display_options: CompletionDisplayOptions::default(),
22266            is_incomplete: false,
22267        }));
22268    }
22269
22270    let snapshot = buffer.read(cx).text_snapshot();
22271    let chars: String = snapshot
22272        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22273        .collect();
22274    let executor = cx.background_executor().clone();
22275
22276    cx.background_spawn(async move {
22277        let mut is_incomplete = false;
22278        let mut completions: Vec<Completion> = Vec::new();
22279        for (scope, snippets) in scopes.into_iter() {
22280            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22281            let mut last_word = chars
22282                .chars()
22283                .take_while(|c| classifier.is_word(*c))
22284                .collect::<String>();
22285            last_word = last_word.chars().rev().collect();
22286
22287            if last_word.is_empty() {
22288                return Ok(CompletionResponse {
22289                    completions: vec![],
22290                    display_options: CompletionDisplayOptions::default(),
22291                    is_incomplete: true,
22292                });
22293            }
22294
22295            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22296            let to_lsp = |point: &text::Anchor| {
22297                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22298                point_to_lsp(end)
22299            };
22300            let lsp_end = to_lsp(&buffer_position);
22301
22302            let candidates = snippets
22303                .iter()
22304                .enumerate()
22305                .flat_map(|(ix, snippet)| {
22306                    snippet
22307                        .prefix
22308                        .iter()
22309                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22310                })
22311                .collect::<Vec<StringMatchCandidate>>();
22312
22313            const MAX_RESULTS: usize = 100;
22314            let mut matches = fuzzy::match_strings(
22315                &candidates,
22316                &last_word,
22317                last_word.chars().any(|c| c.is_uppercase()),
22318                true,
22319                MAX_RESULTS,
22320                &Default::default(),
22321                executor.clone(),
22322            )
22323            .await;
22324
22325            if matches.len() >= MAX_RESULTS {
22326                is_incomplete = true;
22327            }
22328
22329            // Remove all candidates where the query's start does not match the start of any word in the candidate
22330            if let Some(query_start) = last_word.chars().next() {
22331                matches.retain(|string_match| {
22332                    split_words(&string_match.string).any(|word| {
22333                        // Check that the first codepoint of the word as lowercase matches the first
22334                        // codepoint of the query as lowercase
22335                        word.chars()
22336                            .flat_map(|codepoint| codepoint.to_lowercase())
22337                            .zip(query_start.to_lowercase())
22338                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22339                    })
22340                });
22341            }
22342
22343            let matched_strings = matches
22344                .into_iter()
22345                .map(|m| m.string)
22346                .collect::<HashSet<_>>();
22347
22348            completions.extend(snippets.iter().filter_map(|snippet| {
22349                let matching_prefix = snippet
22350                    .prefix
22351                    .iter()
22352                    .find(|prefix| matched_strings.contains(*prefix))?;
22353                let start = as_offset - last_word.len();
22354                let start = snapshot.anchor_before(start);
22355                let range = start..buffer_position;
22356                let lsp_start = to_lsp(&start);
22357                let lsp_range = lsp::Range {
22358                    start: lsp_start,
22359                    end: lsp_end,
22360                };
22361                Some(Completion {
22362                    replace_range: range,
22363                    new_text: snippet.body.clone(),
22364                    source: CompletionSource::Lsp {
22365                        insert_range: None,
22366                        server_id: LanguageServerId(usize::MAX),
22367                        resolved: true,
22368                        lsp_completion: Box::new(lsp::CompletionItem {
22369                            label: snippet.prefix.first().unwrap().clone(),
22370                            kind: Some(CompletionItemKind::SNIPPET),
22371                            label_details: snippet.description.as_ref().map(|description| {
22372                                lsp::CompletionItemLabelDetails {
22373                                    detail: Some(description.clone()),
22374                                    description: None,
22375                                }
22376                            }),
22377                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22378                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22379                                lsp::InsertReplaceEdit {
22380                                    new_text: snippet.body.clone(),
22381                                    insert: lsp_range,
22382                                    replace: lsp_range,
22383                                },
22384                            )),
22385                            filter_text: Some(snippet.body.clone()),
22386                            sort_text: Some(char::MAX.to_string()),
22387                            ..lsp::CompletionItem::default()
22388                        }),
22389                        lsp_defaults: None,
22390                    },
22391                    label: CodeLabel {
22392                        text: matching_prefix.clone(),
22393                        runs: Vec::new(),
22394                        filter_range: 0..matching_prefix.len(),
22395                    },
22396                    icon_path: None,
22397                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22398                        single_line: snippet.name.clone().into(),
22399                        plain_text: snippet
22400                            .description
22401                            .clone()
22402                            .map(|description| description.into()),
22403                    }),
22404                    insert_text_mode: None,
22405                    confirm: None,
22406                })
22407            }))
22408        }
22409
22410        Ok(CompletionResponse {
22411            completions,
22412            display_options: CompletionDisplayOptions::default(),
22413            is_incomplete,
22414        })
22415    })
22416}
22417
22418impl CompletionProvider for Entity<Project> {
22419    fn completions(
22420        &self,
22421        _excerpt_id: ExcerptId,
22422        buffer: &Entity<Buffer>,
22423        buffer_position: text::Anchor,
22424        options: CompletionContext,
22425        _window: &mut Window,
22426        cx: &mut Context<Editor>,
22427    ) -> Task<Result<Vec<CompletionResponse>>> {
22428        self.update(cx, |project, cx| {
22429            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22430            let project_completions = project.completions(buffer, buffer_position, options, cx);
22431            cx.background_spawn(async move {
22432                let mut responses = project_completions.await?;
22433                let snippets = snippets.await?;
22434                if !snippets.completions.is_empty() {
22435                    responses.push(snippets);
22436                }
22437                Ok(responses)
22438            })
22439        })
22440    }
22441
22442    fn resolve_completions(
22443        &self,
22444        buffer: Entity<Buffer>,
22445        completion_indices: Vec<usize>,
22446        completions: Rc<RefCell<Box<[Completion]>>>,
22447        cx: &mut Context<Editor>,
22448    ) -> Task<Result<bool>> {
22449        self.update(cx, |project, cx| {
22450            project.lsp_store().update(cx, |lsp_store, cx| {
22451                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22452            })
22453        })
22454    }
22455
22456    fn apply_additional_edits_for_completion(
22457        &self,
22458        buffer: Entity<Buffer>,
22459        completions: Rc<RefCell<Box<[Completion]>>>,
22460        completion_index: usize,
22461        push_to_history: bool,
22462        cx: &mut Context<Editor>,
22463    ) -> Task<Result<Option<language::Transaction>>> {
22464        self.update(cx, |project, cx| {
22465            project.lsp_store().update(cx, |lsp_store, cx| {
22466                lsp_store.apply_additional_edits_for_completion(
22467                    buffer,
22468                    completions,
22469                    completion_index,
22470                    push_to_history,
22471                    cx,
22472                )
22473            })
22474        })
22475    }
22476
22477    fn is_completion_trigger(
22478        &self,
22479        buffer: &Entity<Buffer>,
22480        position: language::Anchor,
22481        text: &str,
22482        trigger_in_words: bool,
22483        menu_is_open: bool,
22484        cx: &mut Context<Editor>,
22485    ) -> bool {
22486        let mut chars = text.chars();
22487        let char = if let Some(char) = chars.next() {
22488            char
22489        } else {
22490            return false;
22491        };
22492        if chars.next().is_some() {
22493            return false;
22494        }
22495
22496        let buffer = buffer.read(cx);
22497        let snapshot = buffer.snapshot();
22498        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22499            return false;
22500        }
22501        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22502        if trigger_in_words && classifier.is_word(char) {
22503            return true;
22504        }
22505
22506        buffer.completion_triggers().contains(text)
22507    }
22508}
22509
22510impl SemanticsProvider for Entity<Project> {
22511    fn hover(
22512        &self,
22513        buffer: &Entity<Buffer>,
22514        position: text::Anchor,
22515        cx: &mut App,
22516    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22517        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22518    }
22519
22520    fn document_highlights(
22521        &self,
22522        buffer: &Entity<Buffer>,
22523        position: text::Anchor,
22524        cx: &mut App,
22525    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22526        Some(self.update(cx, |project, cx| {
22527            project.document_highlights(buffer, position, cx)
22528        }))
22529    }
22530
22531    fn definitions(
22532        &self,
22533        buffer: &Entity<Buffer>,
22534        position: text::Anchor,
22535        kind: GotoDefinitionKind,
22536        cx: &mut App,
22537    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22538        Some(self.update(cx, |project, cx| match kind {
22539            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22540            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22541            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22542            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22543        }))
22544    }
22545
22546    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22547        self.update(cx, |project, cx| {
22548            if project
22549                .active_debug_session(cx)
22550                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22551            {
22552                return true;
22553            }
22554
22555            buffer.update(cx, |buffer, cx| {
22556                project.any_language_server_supports_inlay_hints(buffer, cx)
22557            })
22558        })
22559    }
22560
22561    fn inline_values(
22562        &self,
22563        buffer_handle: Entity<Buffer>,
22564        range: Range<text::Anchor>,
22565        cx: &mut App,
22566    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22567        self.update(cx, |project, cx| {
22568            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22569
22570            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22571        })
22572    }
22573
22574    fn inlay_hints(
22575        &self,
22576        buffer_handle: Entity<Buffer>,
22577        range: Range<text::Anchor>,
22578        cx: &mut App,
22579    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22580        Some(self.update(cx, |project, cx| {
22581            project.inlay_hints(buffer_handle, range, cx)
22582        }))
22583    }
22584
22585    fn resolve_inlay_hint(
22586        &self,
22587        hint: InlayHint,
22588        buffer_handle: Entity<Buffer>,
22589        server_id: LanguageServerId,
22590        cx: &mut App,
22591    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22592        Some(self.update(cx, |project, cx| {
22593            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22594        }))
22595    }
22596
22597    fn range_for_rename(
22598        &self,
22599        buffer: &Entity<Buffer>,
22600        position: text::Anchor,
22601        cx: &mut App,
22602    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22603        Some(self.update(cx, |project, cx| {
22604            let buffer = buffer.clone();
22605            let task = project.prepare_rename(buffer.clone(), position, cx);
22606            cx.spawn(async move |_, cx| {
22607                Ok(match task.await? {
22608                    PrepareRenameResponse::Success(range) => Some(range),
22609                    PrepareRenameResponse::InvalidPosition => None,
22610                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22611                        // Fallback on using TreeSitter info to determine identifier range
22612                        buffer.read_with(cx, |buffer, _| {
22613                            let snapshot = buffer.snapshot();
22614                            let (range, kind) = snapshot.surrounding_word(position, false);
22615                            if kind != Some(CharKind::Word) {
22616                                return None;
22617                            }
22618                            Some(
22619                                snapshot.anchor_before(range.start)
22620                                    ..snapshot.anchor_after(range.end),
22621                            )
22622                        })?
22623                    }
22624                })
22625            })
22626        }))
22627    }
22628
22629    fn perform_rename(
22630        &self,
22631        buffer: &Entity<Buffer>,
22632        position: text::Anchor,
22633        new_name: String,
22634        cx: &mut App,
22635    ) -> Option<Task<Result<ProjectTransaction>>> {
22636        Some(self.update(cx, |project, cx| {
22637            project.perform_rename(buffer.clone(), position, new_name, cx)
22638        }))
22639    }
22640}
22641
22642fn inlay_hint_settings(
22643    location: Anchor,
22644    snapshot: &MultiBufferSnapshot,
22645    cx: &mut Context<Editor>,
22646) -> InlayHintSettings {
22647    let file = snapshot.file_at(location);
22648    let language = snapshot.language_at(location).map(|l| l.name());
22649    language_settings(language, file, cx).inlay_hints
22650}
22651
22652fn consume_contiguous_rows(
22653    contiguous_row_selections: &mut Vec<Selection<Point>>,
22654    selection: &Selection<Point>,
22655    display_map: &DisplaySnapshot,
22656    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22657) -> (MultiBufferRow, MultiBufferRow) {
22658    contiguous_row_selections.push(selection.clone());
22659    let start_row = starting_row(selection, display_map);
22660    let mut end_row = ending_row(selection, display_map);
22661
22662    while let Some(next_selection) = selections.peek() {
22663        if next_selection.start.row <= end_row.0 {
22664            end_row = ending_row(next_selection, display_map);
22665            contiguous_row_selections.push(selections.next().unwrap().clone());
22666        } else {
22667            break;
22668        }
22669    }
22670    (start_row, end_row)
22671}
22672
22673fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22674    if selection.start.column > 0 {
22675        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22676    } else {
22677        MultiBufferRow(selection.start.row)
22678    }
22679}
22680
22681fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22682    if next_selection.end.column > 0 || next_selection.is_empty() {
22683        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22684    } else {
22685        MultiBufferRow(next_selection.end.row)
22686    }
22687}
22688
22689impl EditorSnapshot {
22690    pub fn remote_selections_in_range<'a>(
22691        &'a self,
22692        range: &'a Range<Anchor>,
22693        collaboration_hub: &dyn CollaborationHub,
22694        cx: &'a App,
22695    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22696        let participant_names = collaboration_hub.user_names(cx);
22697        let participant_indices = collaboration_hub.user_participant_indices(cx);
22698        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22699        let collaborators_by_replica_id = collaborators_by_peer_id
22700            .values()
22701            .map(|collaborator| (collaborator.replica_id, collaborator))
22702            .collect::<HashMap<_, _>>();
22703        self.buffer_snapshot
22704            .selections_in_range(range, false)
22705            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22706                if replica_id == AGENT_REPLICA_ID {
22707                    Some(RemoteSelection {
22708                        replica_id,
22709                        selection,
22710                        cursor_shape,
22711                        line_mode,
22712                        collaborator_id: CollaboratorId::Agent,
22713                        user_name: Some("Agent".into()),
22714                        color: cx.theme().players().agent(),
22715                    })
22716                } else {
22717                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22718                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22719                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22720                    Some(RemoteSelection {
22721                        replica_id,
22722                        selection,
22723                        cursor_shape,
22724                        line_mode,
22725                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22726                        user_name,
22727                        color: if let Some(index) = participant_index {
22728                            cx.theme().players().color_for_participant(index.0)
22729                        } else {
22730                            cx.theme().players().absent()
22731                        },
22732                    })
22733                }
22734            })
22735    }
22736
22737    pub fn hunks_for_ranges(
22738        &self,
22739        ranges: impl IntoIterator<Item = Range<Point>>,
22740    ) -> Vec<MultiBufferDiffHunk> {
22741        let mut hunks = Vec::new();
22742        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22743            HashMap::default();
22744        for query_range in ranges {
22745            let query_rows =
22746                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22747            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22748                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22749            ) {
22750                // Include deleted hunks that are adjacent to the query range, because
22751                // otherwise they would be missed.
22752                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22753                if hunk.status().is_deleted() {
22754                    intersects_range |= hunk.row_range.start == query_rows.end;
22755                    intersects_range |= hunk.row_range.end == query_rows.start;
22756                }
22757                if intersects_range {
22758                    if !processed_buffer_rows
22759                        .entry(hunk.buffer_id)
22760                        .or_default()
22761                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22762                    {
22763                        continue;
22764                    }
22765                    hunks.push(hunk);
22766                }
22767            }
22768        }
22769
22770        hunks
22771    }
22772
22773    fn display_diff_hunks_for_rows<'a>(
22774        &'a self,
22775        display_rows: Range<DisplayRow>,
22776        folded_buffers: &'a HashSet<BufferId>,
22777    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22778        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22779        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22780
22781        self.buffer_snapshot
22782            .diff_hunks_in_range(buffer_start..buffer_end)
22783            .filter_map(|hunk| {
22784                if folded_buffers.contains(&hunk.buffer_id) {
22785                    return None;
22786                }
22787
22788                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22789                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22790
22791                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22792                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22793
22794                let display_hunk = if hunk_display_start.column() != 0 {
22795                    DisplayDiffHunk::Folded {
22796                        display_row: hunk_display_start.row(),
22797                    }
22798                } else {
22799                    let mut end_row = hunk_display_end.row();
22800                    if hunk_display_end.column() > 0 {
22801                        end_row.0 += 1;
22802                    }
22803                    let is_created_file = hunk.is_created_file();
22804                    DisplayDiffHunk::Unfolded {
22805                        status: hunk.status(),
22806                        diff_base_byte_range: hunk.diff_base_byte_range,
22807                        display_row_range: hunk_display_start.row()..end_row,
22808                        multi_buffer_range: Anchor::range_in_buffer(
22809                            hunk.excerpt_id,
22810                            hunk.buffer_id,
22811                            hunk.buffer_range,
22812                        ),
22813                        is_created_file,
22814                    }
22815                };
22816
22817                Some(display_hunk)
22818            })
22819    }
22820
22821    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22822        self.display_snapshot.buffer_snapshot.language_at(position)
22823    }
22824
22825    pub fn is_focused(&self) -> bool {
22826        self.is_focused
22827    }
22828
22829    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22830        self.placeholder_text.as_ref()
22831    }
22832
22833    pub fn scroll_position(&self) -> gpui::Point<f32> {
22834        self.scroll_anchor.scroll_position(&self.display_snapshot)
22835    }
22836
22837    fn gutter_dimensions(
22838        &self,
22839        font_id: FontId,
22840        font_size: Pixels,
22841        max_line_number_width: Pixels,
22842        cx: &App,
22843    ) -> Option<GutterDimensions> {
22844        if !self.show_gutter {
22845            return None;
22846        }
22847
22848        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22849        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22850
22851        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22852            matches!(
22853                ProjectSettings::get_global(cx).git.git_gutter,
22854                Some(GitGutterSetting::TrackedFiles)
22855            )
22856        });
22857        let gutter_settings = EditorSettings::get_global(cx).gutter;
22858        let show_line_numbers = self
22859            .show_line_numbers
22860            .unwrap_or(gutter_settings.line_numbers);
22861        let line_gutter_width = if show_line_numbers {
22862            // Avoid flicker-like gutter resizes when the line number gains another digit by
22863            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22864            let min_width_for_number_on_gutter =
22865                ch_advance * gutter_settings.min_line_number_digits as f32;
22866            max_line_number_width.max(min_width_for_number_on_gutter)
22867        } else {
22868            0.0.into()
22869        };
22870
22871        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22872        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22873
22874        let git_blame_entries_width =
22875            self.git_blame_gutter_max_author_length
22876                .map(|max_author_length| {
22877                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22878                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22879
22880                    /// The number of characters to dedicate to gaps and margins.
22881                    const SPACING_WIDTH: usize = 4;
22882
22883                    let max_char_count = max_author_length.min(renderer.max_author_length())
22884                        + ::git::SHORT_SHA_LENGTH
22885                        + MAX_RELATIVE_TIMESTAMP.len()
22886                        + SPACING_WIDTH;
22887
22888                    ch_advance * max_char_count
22889                });
22890
22891        let is_singleton = self.buffer_snapshot.is_singleton();
22892
22893        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22894        left_padding += if !is_singleton {
22895            ch_width * 4.0
22896        } else if show_runnables || show_breakpoints {
22897            ch_width * 3.0
22898        } else if show_git_gutter && show_line_numbers {
22899            ch_width * 2.0
22900        } else if show_git_gutter || show_line_numbers {
22901            ch_width
22902        } else {
22903            px(0.)
22904        };
22905
22906        let shows_folds = is_singleton && gutter_settings.folds;
22907
22908        let right_padding = if shows_folds && show_line_numbers {
22909            ch_width * 4.0
22910        } else if shows_folds || (!is_singleton && show_line_numbers) {
22911            ch_width * 3.0
22912        } else if show_line_numbers {
22913            ch_width
22914        } else {
22915            px(0.)
22916        };
22917
22918        Some(GutterDimensions {
22919            left_padding,
22920            right_padding,
22921            width: line_gutter_width + left_padding + right_padding,
22922            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22923            git_blame_entries_width,
22924        })
22925    }
22926
22927    pub fn render_crease_toggle(
22928        &self,
22929        buffer_row: MultiBufferRow,
22930        row_contains_cursor: bool,
22931        editor: Entity<Editor>,
22932        window: &mut Window,
22933        cx: &mut App,
22934    ) -> Option<AnyElement> {
22935        let folded = self.is_line_folded(buffer_row);
22936        let mut is_foldable = false;
22937
22938        if let Some(crease) = self
22939            .crease_snapshot
22940            .query_row(buffer_row, &self.buffer_snapshot)
22941        {
22942            is_foldable = true;
22943            match crease {
22944                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22945                    if let Some(render_toggle) = render_toggle {
22946                        let toggle_callback =
22947                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22948                                if folded {
22949                                    editor.update(cx, |editor, cx| {
22950                                        editor.fold_at(buffer_row, window, cx)
22951                                    });
22952                                } else {
22953                                    editor.update(cx, |editor, cx| {
22954                                        editor.unfold_at(buffer_row, window, cx)
22955                                    });
22956                                }
22957                            });
22958                        return Some((render_toggle)(
22959                            buffer_row,
22960                            folded,
22961                            toggle_callback,
22962                            window,
22963                            cx,
22964                        ));
22965                    }
22966                }
22967            }
22968        }
22969
22970        is_foldable |= self.starts_indent(buffer_row);
22971
22972        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22973            Some(
22974                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22975                    .toggle_state(folded)
22976                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22977                        if folded {
22978                            this.unfold_at(buffer_row, window, cx);
22979                        } else {
22980                            this.fold_at(buffer_row, window, cx);
22981                        }
22982                    }))
22983                    .into_any_element(),
22984            )
22985        } else {
22986            None
22987        }
22988    }
22989
22990    pub fn render_crease_trailer(
22991        &self,
22992        buffer_row: MultiBufferRow,
22993        window: &mut Window,
22994        cx: &mut App,
22995    ) -> Option<AnyElement> {
22996        let folded = self.is_line_folded(buffer_row);
22997        if let Crease::Inline { render_trailer, .. } = self
22998            .crease_snapshot
22999            .query_row(buffer_row, &self.buffer_snapshot)?
23000        {
23001            let render_trailer = render_trailer.as_ref()?;
23002            Some(render_trailer(buffer_row, folded, window, cx))
23003        } else {
23004            None
23005        }
23006    }
23007}
23008
23009impl Deref for EditorSnapshot {
23010    type Target = DisplaySnapshot;
23011
23012    fn deref(&self) -> &Self::Target {
23013        &self.display_snapshot
23014    }
23015}
23016
23017#[derive(Clone, Debug, PartialEq, Eq)]
23018pub enum EditorEvent {
23019    InputIgnored {
23020        text: Arc<str>,
23021    },
23022    InputHandled {
23023        utf16_range_to_replace: Option<Range<isize>>,
23024        text: Arc<str>,
23025    },
23026    ExcerptsAdded {
23027        buffer: Entity<Buffer>,
23028        predecessor: ExcerptId,
23029        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23030    },
23031    ExcerptsRemoved {
23032        ids: Vec<ExcerptId>,
23033        removed_buffer_ids: Vec<BufferId>,
23034    },
23035    BufferFoldToggled {
23036        ids: Vec<ExcerptId>,
23037        folded: bool,
23038    },
23039    ExcerptsEdited {
23040        ids: Vec<ExcerptId>,
23041    },
23042    ExcerptsExpanded {
23043        ids: Vec<ExcerptId>,
23044    },
23045    BufferEdited,
23046    Edited {
23047        transaction_id: clock::Lamport,
23048    },
23049    Reparsed(BufferId),
23050    Focused,
23051    FocusedIn,
23052    Blurred,
23053    DirtyChanged,
23054    Saved,
23055    TitleChanged,
23056    SelectionsChanged {
23057        local: bool,
23058    },
23059    ScrollPositionChanged {
23060        local: bool,
23061        autoscroll: bool,
23062    },
23063    TransactionUndone {
23064        transaction_id: clock::Lamport,
23065    },
23066    TransactionBegun {
23067        transaction_id: clock::Lamport,
23068    },
23069    CursorShapeChanged,
23070    BreadcrumbsChanged,
23071    PushedToNavHistory {
23072        anchor: Anchor,
23073        is_deactivate: bool,
23074    },
23075}
23076
23077impl EventEmitter<EditorEvent> for Editor {}
23078
23079impl Focusable for Editor {
23080    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23081        self.focus_handle.clone()
23082    }
23083}
23084
23085impl Render for Editor {
23086    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23087        let settings = ThemeSettings::get_global(cx);
23088
23089        let mut text_style = match self.mode {
23090            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23091                color: cx.theme().colors().editor_foreground,
23092                font_family: settings.ui_font.family.clone(),
23093                font_features: settings.ui_font.features.clone(),
23094                font_fallbacks: settings.ui_font.fallbacks.clone(),
23095                font_size: rems(0.875).into(),
23096                font_weight: settings.ui_font.weight,
23097                line_height: relative(settings.buffer_line_height.value()),
23098                ..Default::default()
23099            },
23100            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23101                color: cx.theme().colors().editor_foreground,
23102                font_family: settings.buffer_font.family.clone(),
23103                font_features: settings.buffer_font.features.clone(),
23104                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23105                font_size: settings.buffer_font_size(cx).into(),
23106                font_weight: settings.buffer_font.weight,
23107                line_height: relative(settings.buffer_line_height.value()),
23108                ..Default::default()
23109            },
23110        };
23111        if let Some(text_style_refinement) = &self.text_style_refinement {
23112            text_style.refine(text_style_refinement)
23113        }
23114
23115        let background = match self.mode {
23116            EditorMode::SingleLine => cx.theme().system().transparent,
23117            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23118            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23119            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23120        };
23121
23122        EditorElement::new(
23123            &cx.entity(),
23124            EditorStyle {
23125                background,
23126                border: cx.theme().colors().border,
23127                local_player: cx.theme().players().local(),
23128                text: text_style,
23129                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23130                syntax: cx.theme().syntax().clone(),
23131                status: cx.theme().status().clone(),
23132                inlay_hints_style: make_inlay_hints_style(cx),
23133                edit_prediction_styles: make_suggestion_styles(cx),
23134                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23135                show_underlines: self.diagnostics_enabled(),
23136            },
23137        )
23138    }
23139}
23140
23141impl EntityInputHandler for Editor {
23142    fn text_for_range(
23143        &mut self,
23144        range_utf16: Range<usize>,
23145        adjusted_range: &mut Option<Range<usize>>,
23146        _: &mut Window,
23147        cx: &mut Context<Self>,
23148    ) -> Option<String> {
23149        let snapshot = self.buffer.read(cx).read(cx);
23150        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23151        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23152        if (start.0..end.0) != range_utf16 {
23153            adjusted_range.replace(start.0..end.0);
23154        }
23155        Some(snapshot.text_for_range(start..end).collect())
23156    }
23157
23158    fn selected_text_range(
23159        &mut self,
23160        ignore_disabled_input: bool,
23161        _: &mut Window,
23162        cx: &mut Context<Self>,
23163    ) -> Option<UTF16Selection> {
23164        // Prevent the IME menu from appearing when holding down an alphabetic key
23165        // while input is disabled.
23166        if !ignore_disabled_input && !self.input_enabled {
23167            return None;
23168        }
23169
23170        let selection = self.selections.newest::<OffsetUtf16>(cx);
23171        let range = selection.range();
23172
23173        Some(UTF16Selection {
23174            range: range.start.0..range.end.0,
23175            reversed: selection.reversed,
23176        })
23177    }
23178
23179    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23180        let snapshot = self.buffer.read(cx).read(cx);
23181        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23182        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23183    }
23184
23185    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23186        self.clear_highlights::<InputComposition>(cx);
23187        self.ime_transaction.take();
23188    }
23189
23190    fn replace_text_in_range(
23191        &mut self,
23192        range_utf16: Option<Range<usize>>,
23193        text: &str,
23194        window: &mut Window,
23195        cx: &mut Context<Self>,
23196    ) {
23197        if !self.input_enabled {
23198            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23199            return;
23200        }
23201
23202        self.transact(window, cx, |this, window, cx| {
23203            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23204                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23205                Some(this.selection_replacement_ranges(range_utf16, cx))
23206            } else {
23207                this.marked_text_ranges(cx)
23208            };
23209
23210            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23211                let newest_selection_id = this.selections.newest_anchor().id;
23212                this.selections
23213                    .all::<OffsetUtf16>(cx)
23214                    .iter()
23215                    .zip(ranges_to_replace.iter())
23216                    .find_map(|(selection, range)| {
23217                        if selection.id == newest_selection_id {
23218                            Some(
23219                                (range.start.0 as isize - selection.head().0 as isize)
23220                                    ..(range.end.0 as isize - selection.head().0 as isize),
23221                            )
23222                        } else {
23223                            None
23224                        }
23225                    })
23226            });
23227
23228            cx.emit(EditorEvent::InputHandled {
23229                utf16_range_to_replace: range_to_replace,
23230                text: text.into(),
23231            });
23232
23233            if let Some(new_selected_ranges) = new_selected_ranges {
23234                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23235                    selections.select_ranges(new_selected_ranges)
23236                });
23237                this.backspace(&Default::default(), window, cx);
23238            }
23239
23240            this.handle_input(text, window, cx);
23241        });
23242
23243        if let Some(transaction) = self.ime_transaction {
23244            self.buffer.update(cx, |buffer, cx| {
23245                buffer.group_until_transaction(transaction, cx);
23246            });
23247        }
23248
23249        self.unmark_text(window, cx);
23250    }
23251
23252    fn replace_and_mark_text_in_range(
23253        &mut self,
23254        range_utf16: Option<Range<usize>>,
23255        text: &str,
23256        new_selected_range_utf16: Option<Range<usize>>,
23257        window: &mut Window,
23258        cx: &mut Context<Self>,
23259    ) {
23260        if !self.input_enabled {
23261            return;
23262        }
23263
23264        let transaction = self.transact(window, cx, |this, window, cx| {
23265            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23266                let snapshot = this.buffer.read(cx).read(cx);
23267                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23268                    for marked_range in &mut marked_ranges {
23269                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23270                        marked_range.start.0 += relative_range_utf16.start;
23271                        marked_range.start =
23272                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23273                        marked_range.end =
23274                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23275                    }
23276                }
23277                Some(marked_ranges)
23278            } else if let Some(range_utf16) = range_utf16 {
23279                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23280                Some(this.selection_replacement_ranges(range_utf16, cx))
23281            } else {
23282                None
23283            };
23284
23285            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23286                let newest_selection_id = this.selections.newest_anchor().id;
23287                this.selections
23288                    .all::<OffsetUtf16>(cx)
23289                    .iter()
23290                    .zip(ranges_to_replace.iter())
23291                    .find_map(|(selection, range)| {
23292                        if selection.id == newest_selection_id {
23293                            Some(
23294                                (range.start.0 as isize - selection.head().0 as isize)
23295                                    ..(range.end.0 as isize - selection.head().0 as isize),
23296                            )
23297                        } else {
23298                            None
23299                        }
23300                    })
23301            });
23302
23303            cx.emit(EditorEvent::InputHandled {
23304                utf16_range_to_replace: range_to_replace,
23305                text: text.into(),
23306            });
23307
23308            if let Some(ranges) = ranges_to_replace {
23309                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23310                    s.select_ranges(ranges)
23311                });
23312            }
23313
23314            let marked_ranges = {
23315                let snapshot = this.buffer.read(cx).read(cx);
23316                this.selections
23317                    .disjoint_anchors()
23318                    .iter()
23319                    .map(|selection| {
23320                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23321                    })
23322                    .collect::<Vec<_>>()
23323            };
23324
23325            if text.is_empty() {
23326                this.unmark_text(window, cx);
23327            } else {
23328                this.highlight_text::<InputComposition>(
23329                    marked_ranges.clone(),
23330                    HighlightStyle {
23331                        underline: Some(UnderlineStyle {
23332                            thickness: px(1.),
23333                            color: None,
23334                            wavy: false,
23335                        }),
23336                        ..Default::default()
23337                    },
23338                    cx,
23339                );
23340            }
23341
23342            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23343            let use_autoclose = this.use_autoclose;
23344            let use_auto_surround = this.use_auto_surround;
23345            this.set_use_autoclose(false);
23346            this.set_use_auto_surround(false);
23347            this.handle_input(text, window, cx);
23348            this.set_use_autoclose(use_autoclose);
23349            this.set_use_auto_surround(use_auto_surround);
23350
23351            if let Some(new_selected_range) = new_selected_range_utf16 {
23352                let snapshot = this.buffer.read(cx).read(cx);
23353                let new_selected_ranges = marked_ranges
23354                    .into_iter()
23355                    .map(|marked_range| {
23356                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23357                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23358                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23359                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23360                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23361                    })
23362                    .collect::<Vec<_>>();
23363
23364                drop(snapshot);
23365                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23366                    selections.select_ranges(new_selected_ranges)
23367                });
23368            }
23369        });
23370
23371        self.ime_transaction = self.ime_transaction.or(transaction);
23372        if let Some(transaction) = self.ime_transaction {
23373            self.buffer.update(cx, |buffer, cx| {
23374                buffer.group_until_transaction(transaction, cx);
23375            });
23376        }
23377
23378        if self.text_highlights::<InputComposition>(cx).is_none() {
23379            self.ime_transaction.take();
23380        }
23381    }
23382
23383    fn bounds_for_range(
23384        &mut self,
23385        range_utf16: Range<usize>,
23386        element_bounds: gpui::Bounds<Pixels>,
23387        window: &mut Window,
23388        cx: &mut Context<Self>,
23389    ) -> Option<gpui::Bounds<Pixels>> {
23390        let text_layout_details = self.text_layout_details(window);
23391        let CharacterDimensions {
23392            em_width,
23393            em_advance,
23394            line_height,
23395        } = self.character_dimensions(window);
23396
23397        let snapshot = self.snapshot(window, cx);
23398        let scroll_position = snapshot.scroll_position();
23399        let scroll_left = scroll_position.x * em_advance;
23400
23401        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23402        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23403            + self.gutter_dimensions.full_width();
23404        let y = line_height * (start.row().as_f32() - scroll_position.y);
23405
23406        Some(Bounds {
23407            origin: element_bounds.origin + point(x, y),
23408            size: size(em_width, line_height),
23409        })
23410    }
23411
23412    fn character_index_for_point(
23413        &mut self,
23414        point: gpui::Point<Pixels>,
23415        _window: &mut Window,
23416        _cx: &mut Context<Self>,
23417    ) -> Option<usize> {
23418        let position_map = self.last_position_map.as_ref()?;
23419        if !position_map.text_hitbox.contains(&point) {
23420            return None;
23421        }
23422        let display_point = position_map.point_for_position(point).previous_valid;
23423        let anchor = position_map
23424            .snapshot
23425            .display_point_to_anchor(display_point, Bias::Left);
23426        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23427        Some(utf16_offset.0)
23428    }
23429}
23430
23431trait SelectionExt {
23432    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23433    fn spanned_rows(
23434        &self,
23435        include_end_if_at_line_start: bool,
23436        map: &DisplaySnapshot,
23437    ) -> Range<MultiBufferRow>;
23438}
23439
23440impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23441    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23442        let start = self
23443            .start
23444            .to_point(&map.buffer_snapshot)
23445            .to_display_point(map);
23446        let end = self
23447            .end
23448            .to_point(&map.buffer_snapshot)
23449            .to_display_point(map);
23450        if self.reversed {
23451            end..start
23452        } else {
23453            start..end
23454        }
23455    }
23456
23457    fn spanned_rows(
23458        &self,
23459        include_end_if_at_line_start: bool,
23460        map: &DisplaySnapshot,
23461    ) -> Range<MultiBufferRow> {
23462        let start = self.start.to_point(&map.buffer_snapshot);
23463        let mut end = self.end.to_point(&map.buffer_snapshot);
23464        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23465            end.row -= 1;
23466        }
23467
23468        let buffer_start = map.prev_line_boundary(start).0;
23469        let buffer_end = map.next_line_boundary(end).0;
23470        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23471    }
23472}
23473
23474impl<T: InvalidationRegion> InvalidationStack<T> {
23475    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23476    where
23477        S: Clone + ToOffset,
23478    {
23479        while let Some(region) = self.last() {
23480            let all_selections_inside_invalidation_ranges =
23481                if selections.len() == region.ranges().len() {
23482                    selections
23483                        .iter()
23484                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23485                        .all(|(selection, invalidation_range)| {
23486                            let head = selection.head().to_offset(buffer);
23487                            invalidation_range.start <= head && invalidation_range.end >= head
23488                        })
23489                } else {
23490                    false
23491                };
23492
23493            if all_selections_inside_invalidation_ranges {
23494                break;
23495            } else {
23496                self.pop();
23497            }
23498        }
23499    }
23500}
23501
23502impl<T> Default for InvalidationStack<T> {
23503    fn default() -> Self {
23504        Self(Default::default())
23505    }
23506}
23507
23508impl<T> Deref for InvalidationStack<T> {
23509    type Target = Vec<T>;
23510
23511    fn deref(&self) -> &Self::Target {
23512        &self.0
23513    }
23514}
23515
23516impl<T> DerefMut for InvalidationStack<T> {
23517    fn deref_mut(&mut self) -> &mut Self::Target {
23518        &mut self.0
23519    }
23520}
23521
23522impl InvalidationRegion for SnippetState {
23523    fn ranges(&self) -> &[Range<Anchor>] {
23524        &self.ranges[self.active_index]
23525    }
23526}
23527
23528fn edit_prediction_edit_text(
23529    current_snapshot: &BufferSnapshot,
23530    edits: &[(Range<Anchor>, String)],
23531    edit_preview: &EditPreview,
23532    include_deletions: bool,
23533    cx: &App,
23534) -> HighlightedText {
23535    let edits = edits
23536        .iter()
23537        .map(|(anchor, text)| {
23538            (
23539                anchor.start.text_anchor..anchor.end.text_anchor,
23540                text.clone(),
23541            )
23542        })
23543        .collect::<Vec<_>>();
23544
23545    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23546}
23547
23548fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23549    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23550    // Just show the raw edit text with basic styling
23551    let mut text = String::new();
23552    let mut highlights = Vec::new();
23553
23554    let insertion_highlight_style = HighlightStyle {
23555        color: Some(cx.theme().colors().text),
23556        ..Default::default()
23557    };
23558
23559    for (_, edit_text) in edits {
23560        let start_offset = text.len();
23561        text.push_str(edit_text);
23562        let end_offset = text.len();
23563
23564        if start_offset < end_offset {
23565            highlights.push((start_offset..end_offset, insertion_highlight_style));
23566        }
23567    }
23568
23569    HighlightedText {
23570        text: text.into(),
23571        highlights,
23572    }
23573}
23574
23575pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23576    match severity {
23577        lsp::DiagnosticSeverity::ERROR => colors.error,
23578        lsp::DiagnosticSeverity::WARNING => colors.warning,
23579        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23580        lsp::DiagnosticSeverity::HINT => colors.info,
23581        _ => colors.ignored,
23582    }
23583}
23584
23585pub fn styled_runs_for_code_label<'a>(
23586    label: &'a CodeLabel,
23587    syntax_theme: &'a theme::SyntaxTheme,
23588) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23589    let fade_out = HighlightStyle {
23590        fade_out: Some(0.35),
23591        ..Default::default()
23592    };
23593
23594    let mut prev_end = label.filter_range.end;
23595    label
23596        .runs
23597        .iter()
23598        .enumerate()
23599        .flat_map(move |(ix, (range, highlight_id))| {
23600            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23601                style
23602            } else {
23603                return Default::default();
23604            };
23605            let mut muted_style = style;
23606            muted_style.highlight(fade_out);
23607
23608            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23609            if range.start >= label.filter_range.end {
23610                if range.start > prev_end {
23611                    runs.push((prev_end..range.start, fade_out));
23612                }
23613                runs.push((range.clone(), muted_style));
23614            } else if range.end <= label.filter_range.end {
23615                runs.push((range.clone(), style));
23616            } else {
23617                runs.push((range.start..label.filter_range.end, style));
23618                runs.push((label.filter_range.end..range.end, muted_style));
23619            }
23620            prev_end = cmp::max(prev_end, range.end);
23621
23622            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23623                runs.push((prev_end..label.text.len(), fade_out));
23624            }
23625
23626            runs
23627        })
23628}
23629
23630pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23631    let mut prev_index = 0;
23632    let mut prev_codepoint: Option<char> = None;
23633    text.char_indices()
23634        .chain([(text.len(), '\0')])
23635        .filter_map(move |(index, codepoint)| {
23636            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23637            let is_boundary = index == text.len()
23638                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23639                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23640            if is_boundary {
23641                let chunk = &text[prev_index..index];
23642                prev_index = index;
23643                Some(chunk)
23644            } else {
23645                None
23646            }
23647        })
23648}
23649
23650pub trait RangeToAnchorExt: Sized {
23651    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23652
23653    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23654        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23655        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23656    }
23657}
23658
23659impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23660    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23661        let start_offset = self.start.to_offset(snapshot);
23662        let end_offset = self.end.to_offset(snapshot);
23663        if start_offset == end_offset {
23664            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23665        } else {
23666            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23667        }
23668    }
23669}
23670
23671pub trait RowExt {
23672    fn as_f32(&self) -> f32;
23673
23674    fn next_row(&self) -> Self;
23675
23676    fn previous_row(&self) -> Self;
23677
23678    fn minus(&self, other: Self) -> u32;
23679}
23680
23681impl RowExt for DisplayRow {
23682    fn as_f32(&self) -> f32 {
23683        self.0 as f32
23684    }
23685
23686    fn next_row(&self) -> Self {
23687        Self(self.0 + 1)
23688    }
23689
23690    fn previous_row(&self) -> Self {
23691        Self(self.0.saturating_sub(1))
23692    }
23693
23694    fn minus(&self, other: Self) -> u32 {
23695        self.0 - other.0
23696    }
23697}
23698
23699impl RowExt for MultiBufferRow {
23700    fn as_f32(&self) -> f32 {
23701        self.0 as f32
23702    }
23703
23704    fn next_row(&self) -> Self {
23705        Self(self.0 + 1)
23706    }
23707
23708    fn previous_row(&self) -> Self {
23709        Self(self.0.saturating_sub(1))
23710    }
23711
23712    fn minus(&self, other: Self) -> u32 {
23713        self.0 - other.0
23714    }
23715}
23716
23717trait RowRangeExt {
23718    type Row;
23719
23720    fn len(&self) -> usize;
23721
23722    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23723}
23724
23725impl RowRangeExt for Range<MultiBufferRow> {
23726    type Row = MultiBufferRow;
23727
23728    fn len(&self) -> usize {
23729        (self.end.0 - self.start.0) as usize
23730    }
23731
23732    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23733        (self.start.0..self.end.0).map(MultiBufferRow)
23734    }
23735}
23736
23737impl RowRangeExt for Range<DisplayRow> {
23738    type Row = DisplayRow;
23739
23740    fn len(&self) -> usize {
23741        (self.end.0 - self.start.0) as usize
23742    }
23743
23744    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23745        (self.start.0..self.end.0).map(DisplayRow)
23746    }
23747}
23748
23749/// If select range has more than one line, we
23750/// just point the cursor to range.start.
23751fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23752    if range.start.row == range.end.row {
23753        range
23754    } else {
23755        range.start..range.start
23756    }
23757}
23758pub struct KillRing(ClipboardItem);
23759impl Global for KillRing {}
23760
23761const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23762
23763enum BreakpointPromptEditAction {
23764    Log,
23765    Condition,
23766    HitCondition,
23767}
23768
23769struct BreakpointPromptEditor {
23770    pub(crate) prompt: Entity<Editor>,
23771    editor: WeakEntity<Editor>,
23772    breakpoint_anchor: Anchor,
23773    breakpoint: Breakpoint,
23774    edit_action: BreakpointPromptEditAction,
23775    block_ids: HashSet<CustomBlockId>,
23776    editor_margins: Arc<Mutex<EditorMargins>>,
23777    _subscriptions: Vec<Subscription>,
23778}
23779
23780impl BreakpointPromptEditor {
23781    const MAX_LINES: u8 = 4;
23782
23783    fn new(
23784        editor: WeakEntity<Editor>,
23785        breakpoint_anchor: Anchor,
23786        breakpoint: Breakpoint,
23787        edit_action: BreakpointPromptEditAction,
23788        window: &mut Window,
23789        cx: &mut Context<Self>,
23790    ) -> Self {
23791        let base_text = match edit_action {
23792            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23793            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23794            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23795        }
23796        .map(|msg| msg.to_string())
23797        .unwrap_or_default();
23798
23799        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23800        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23801
23802        let prompt = cx.new(|cx| {
23803            let mut prompt = Editor::new(
23804                EditorMode::AutoHeight {
23805                    min_lines: 1,
23806                    max_lines: Some(Self::MAX_LINES as usize),
23807                },
23808                buffer,
23809                None,
23810                window,
23811                cx,
23812            );
23813            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23814            prompt.set_show_cursor_when_unfocused(false, cx);
23815            prompt.set_placeholder_text(
23816                match edit_action {
23817                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23818                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23819                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23820                },
23821                cx,
23822            );
23823
23824            prompt
23825        });
23826
23827        Self {
23828            prompt,
23829            editor,
23830            breakpoint_anchor,
23831            breakpoint,
23832            edit_action,
23833            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23834            block_ids: Default::default(),
23835            _subscriptions: vec![],
23836        }
23837    }
23838
23839    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23840        self.block_ids.extend(block_ids)
23841    }
23842
23843    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23844        if let Some(editor) = self.editor.upgrade() {
23845            let message = self
23846                .prompt
23847                .read(cx)
23848                .buffer
23849                .read(cx)
23850                .as_singleton()
23851                .expect("A multi buffer in breakpoint prompt isn't possible")
23852                .read(cx)
23853                .as_rope()
23854                .to_string();
23855
23856            editor.update(cx, |editor, cx| {
23857                editor.edit_breakpoint_at_anchor(
23858                    self.breakpoint_anchor,
23859                    self.breakpoint.clone(),
23860                    match self.edit_action {
23861                        BreakpointPromptEditAction::Log => {
23862                            BreakpointEditAction::EditLogMessage(message.into())
23863                        }
23864                        BreakpointPromptEditAction::Condition => {
23865                            BreakpointEditAction::EditCondition(message.into())
23866                        }
23867                        BreakpointPromptEditAction::HitCondition => {
23868                            BreakpointEditAction::EditHitCondition(message.into())
23869                        }
23870                    },
23871                    cx,
23872                );
23873
23874                editor.remove_blocks(self.block_ids.clone(), None, cx);
23875                cx.focus_self(window);
23876            });
23877        }
23878    }
23879
23880    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23881        self.editor
23882            .update(cx, |editor, cx| {
23883                editor.remove_blocks(self.block_ids.clone(), None, cx);
23884                window.focus(&editor.focus_handle);
23885            })
23886            .log_err();
23887    }
23888
23889    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23890        let settings = ThemeSettings::get_global(cx);
23891        let text_style = TextStyle {
23892            color: if self.prompt.read(cx).read_only(cx) {
23893                cx.theme().colors().text_disabled
23894            } else {
23895                cx.theme().colors().text
23896            },
23897            font_family: settings.buffer_font.family.clone(),
23898            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23899            font_size: settings.buffer_font_size(cx).into(),
23900            font_weight: settings.buffer_font.weight,
23901            line_height: relative(settings.buffer_line_height.value()),
23902            ..Default::default()
23903        };
23904        EditorElement::new(
23905            &self.prompt,
23906            EditorStyle {
23907                background: cx.theme().colors().editor_background,
23908                local_player: cx.theme().players().local(),
23909                text: text_style,
23910                ..Default::default()
23911            },
23912        )
23913    }
23914}
23915
23916impl Render for BreakpointPromptEditor {
23917    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23918        let editor_margins = *self.editor_margins.lock();
23919        let gutter_dimensions = editor_margins.gutter;
23920        h_flex()
23921            .key_context("Editor")
23922            .bg(cx.theme().colors().editor_background)
23923            .border_y_1()
23924            .border_color(cx.theme().status().info_border)
23925            .size_full()
23926            .py(window.line_height() / 2.5)
23927            .on_action(cx.listener(Self::confirm))
23928            .on_action(cx.listener(Self::cancel))
23929            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23930            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23931    }
23932}
23933
23934impl Focusable for BreakpointPromptEditor {
23935    fn focus_handle(&self, cx: &App) -> FocusHandle {
23936        self.prompt.focus_handle(cx)
23937    }
23938}
23939
23940fn all_edits_insertions_or_deletions(
23941    edits: &Vec<(Range<Anchor>, String)>,
23942    snapshot: &MultiBufferSnapshot,
23943) -> bool {
23944    let mut all_insertions = true;
23945    let mut all_deletions = true;
23946
23947    for (range, new_text) in edits.iter() {
23948        let range_is_empty = range.to_offset(snapshot).is_empty();
23949        let text_is_empty = new_text.is_empty();
23950
23951        if range_is_empty != text_is_empty {
23952            if range_is_empty {
23953                all_deletions = false;
23954            } else {
23955                all_insertions = false;
23956            }
23957        } else {
23958            return false;
23959        }
23960
23961        if !all_insertions && !all_deletions {
23962            return false;
23963        }
23964    }
23965    all_insertions || all_deletions
23966}
23967
23968struct MissingEditPredictionKeybindingTooltip;
23969
23970impl Render for MissingEditPredictionKeybindingTooltip {
23971    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23972        ui::tooltip_container(window, cx, |container, _, cx| {
23973            container
23974                .flex_shrink_0()
23975                .max_w_80()
23976                .min_h(rems_from_px(124.))
23977                .justify_between()
23978                .child(
23979                    v_flex()
23980                        .flex_1()
23981                        .text_ui_sm(cx)
23982                        .child(Label::new("Conflict with Accept Keybinding"))
23983                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23984                )
23985                .child(
23986                    h_flex()
23987                        .pb_1()
23988                        .gap_1()
23989                        .items_end()
23990                        .w_full()
23991                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23992                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23993                        }))
23994                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23995                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23996                        })),
23997                )
23998        })
23999    }
24000}
24001
24002#[derive(Debug, Clone, Copy, PartialEq)]
24003pub struct LineHighlight {
24004    pub background: Background,
24005    pub border: Option<gpui::Hsla>,
24006    pub include_gutter: bool,
24007    pub type_id: Option<TypeId>,
24008}
24009
24010struct LineManipulationResult {
24011    pub new_text: String,
24012    pub line_count_before: usize,
24013    pub line_count_after: usize,
24014}
24015
24016fn render_diff_hunk_controls(
24017    row: u32,
24018    status: &DiffHunkStatus,
24019    hunk_range: Range<Anchor>,
24020    is_created_file: bool,
24021    line_height: Pixels,
24022    editor: &Entity<Editor>,
24023    _window: &mut Window,
24024    cx: &mut App,
24025) -> AnyElement {
24026    h_flex()
24027        .h(line_height)
24028        .mr_1()
24029        .gap_1()
24030        .px_0p5()
24031        .pb_1()
24032        .border_x_1()
24033        .border_b_1()
24034        .border_color(cx.theme().colors().border_variant)
24035        .rounded_b_lg()
24036        .bg(cx.theme().colors().editor_background)
24037        .gap_1()
24038        .block_mouse_except_scroll()
24039        .shadow_md()
24040        .child(if status.has_secondary_hunk() {
24041            Button::new(("stage", row as u64), "Stage")
24042                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24043                .tooltip({
24044                    let focus_handle = editor.focus_handle(cx);
24045                    move |window, cx| {
24046                        Tooltip::for_action_in(
24047                            "Stage Hunk",
24048                            &::git::ToggleStaged,
24049                            &focus_handle,
24050                            window,
24051                            cx,
24052                        )
24053                    }
24054                })
24055                .on_click({
24056                    let editor = editor.clone();
24057                    move |_event, _window, cx| {
24058                        editor.update(cx, |editor, cx| {
24059                            editor.stage_or_unstage_diff_hunks(
24060                                true,
24061                                vec![hunk_range.start..hunk_range.start],
24062                                cx,
24063                            );
24064                        });
24065                    }
24066                })
24067        } else {
24068            Button::new(("unstage", row as u64), "Unstage")
24069                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24070                .tooltip({
24071                    let focus_handle = editor.focus_handle(cx);
24072                    move |window, cx| {
24073                        Tooltip::for_action_in(
24074                            "Unstage Hunk",
24075                            &::git::ToggleStaged,
24076                            &focus_handle,
24077                            window,
24078                            cx,
24079                        )
24080                    }
24081                })
24082                .on_click({
24083                    let editor = editor.clone();
24084                    move |_event, _window, cx| {
24085                        editor.update(cx, |editor, cx| {
24086                            editor.stage_or_unstage_diff_hunks(
24087                                false,
24088                                vec![hunk_range.start..hunk_range.start],
24089                                cx,
24090                            );
24091                        });
24092                    }
24093                })
24094        })
24095        .child(
24096            Button::new(("restore", row as u64), "Restore")
24097                .tooltip({
24098                    let focus_handle = editor.focus_handle(cx);
24099                    move |window, cx| {
24100                        Tooltip::for_action_in(
24101                            "Restore Hunk",
24102                            &::git::Restore,
24103                            &focus_handle,
24104                            window,
24105                            cx,
24106                        )
24107                    }
24108                })
24109                .on_click({
24110                    let editor = editor.clone();
24111                    move |_event, window, cx| {
24112                        editor.update(cx, |editor, cx| {
24113                            let snapshot = editor.snapshot(window, cx);
24114                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24115                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24116                        });
24117                    }
24118                })
24119                .disabled(is_created_file),
24120        )
24121        .when(
24122            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24123            |el| {
24124                el.child(
24125                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24126                        .shape(IconButtonShape::Square)
24127                        .icon_size(IconSize::Small)
24128                        // .disabled(!has_multiple_hunks)
24129                        .tooltip({
24130                            let focus_handle = editor.focus_handle(cx);
24131                            move |window, cx| {
24132                                Tooltip::for_action_in(
24133                                    "Next Hunk",
24134                                    &GoToHunk,
24135                                    &focus_handle,
24136                                    window,
24137                                    cx,
24138                                )
24139                            }
24140                        })
24141                        .on_click({
24142                            let editor = editor.clone();
24143                            move |_event, window, cx| {
24144                                editor.update(cx, |editor, cx| {
24145                                    let snapshot = editor.snapshot(window, cx);
24146                                    let position =
24147                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24148                                    editor.go_to_hunk_before_or_after_position(
24149                                        &snapshot,
24150                                        position,
24151                                        Direction::Next,
24152                                        window,
24153                                        cx,
24154                                    );
24155                                    editor.expand_selected_diff_hunks(cx);
24156                                });
24157                            }
24158                        }),
24159                )
24160                .child(
24161                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24162                        .shape(IconButtonShape::Square)
24163                        .icon_size(IconSize::Small)
24164                        // .disabled(!has_multiple_hunks)
24165                        .tooltip({
24166                            let focus_handle = editor.focus_handle(cx);
24167                            move |window, cx| {
24168                                Tooltip::for_action_in(
24169                                    "Previous Hunk",
24170                                    &GoToPreviousHunk,
24171                                    &focus_handle,
24172                                    window,
24173                                    cx,
24174                                )
24175                            }
24176                        })
24177                        .on_click({
24178                            let editor = editor.clone();
24179                            move |_event, window, cx| {
24180                                editor.update(cx, |editor, cx| {
24181                                    let snapshot = editor.snapshot(window, cx);
24182                                    let point =
24183                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24184                                    editor.go_to_hunk_before_or_after_position(
24185                                        &snapshot,
24186                                        point,
24187                                        Direction::Prev,
24188                                        window,
24189                                        cx,
24190                                    );
24191                                    editor.expand_selected_diff_hunks(cx);
24192                                });
24193                            }
24194                        }),
24195                )
24196            },
24197        )
24198        .into_any_element()
24199}
24200
24201pub fn multibuffer_context_lines(cx: &App) -> u32 {
24202    EditorSettings::try_get(cx)
24203        .map(|settings| settings.excerpt_context_lines)
24204        .unwrap_or(2)
24205        .clamp(1, 32)
24206}