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, CompletionIntent, CompletionResponse,
  151    CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, Location, LocationLink,
  152    PrepareRenameResponse, Project, ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  153    debugger::breakpoint_store::Breakpoint,
  154    debugger::{
  155        breakpoint_store::{
  156            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  157            BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
  164    project_settings::{GitGutterSetting, ProjectSettings},
  165};
  166use rand::{seq::SliceRandom, thread_rng};
  167use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  168use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  169use selections_collection::{
  170    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  171};
  172use serde::{Deserialize, Serialize};
  173use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  174use smallvec::{SmallVec, smallvec};
  175use snippet::Snippet;
  176use std::{
  177    any::TypeId,
  178    borrow::Cow,
  179    cell::OnceCell,
  180    cell::RefCell,
  181    cmp::{self, Ordering, Reverse},
  182    iter::Peekable,
  183    mem,
  184    num::NonZeroU32,
  185    ops::Not,
  186    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  187    path::{Path, PathBuf},
  188    rc::Rc,
  189    sync::Arc,
  190    time::{Duration, Instant},
  191};
  192use sum_tree::TreeMap;
  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);
  229const 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    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1034    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1035    hard_wrap: Option<usize>,
 1036    project: Option<Entity<Project>>,
 1037    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1038    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1039    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1040    blink_manager: Entity<BlinkManager>,
 1041    show_cursor_names: bool,
 1042    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1043    pub show_local_selections: bool,
 1044    mode: EditorMode,
 1045    show_breadcrumbs: bool,
 1046    show_gutter: bool,
 1047    show_scrollbars: ScrollbarAxes,
 1048    minimap_visibility: MinimapVisibility,
 1049    offset_content: bool,
 1050    disable_expand_excerpt_buttons: bool,
 1051    show_line_numbers: Option<bool>,
 1052    use_relative_line_numbers: Option<bool>,
 1053    show_git_diff_gutter: Option<bool>,
 1054    show_code_actions: Option<bool>,
 1055    show_runnables: Option<bool>,
 1056    show_breakpoints: Option<bool>,
 1057    show_wrap_guides: Option<bool>,
 1058    show_indent_guides: Option<bool>,
 1059    placeholder_text: Option<Arc<str>>,
 1060    highlight_order: usize,
 1061    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1062    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1063    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1064    scrollbar_marker_state: ScrollbarMarkerState,
 1065    active_indent_guides_state: ActiveIndentGuidesState,
 1066    nav_history: Option<ItemNavHistory>,
 1067    context_menu: RefCell<Option<CodeContextMenu>>,
 1068    context_menu_options: Option<ContextMenuOptions>,
 1069    mouse_context_menu: Option<MouseContextMenu>,
 1070    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1071    inline_blame_popover: Option<InlineBlamePopover>,
 1072    inline_blame_popover_show_task: Option<Task<()>>,
 1073    signature_help_state: SignatureHelpState,
 1074    auto_signature_help: Option<bool>,
 1075    find_all_references_task_sources: Vec<Anchor>,
 1076    next_completion_id: CompletionId,
 1077    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1078    code_actions_task: Option<Task<Result<()>>>,
 1079    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1080    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1081    document_highlights_task: Option<Task<()>>,
 1082    linked_editing_range_task: Option<Task<Option<()>>>,
 1083    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1084    pending_rename: Option<RenameState>,
 1085    searchable: bool,
 1086    cursor_shape: CursorShape,
 1087    current_line_highlight: Option<CurrentLineHighlight>,
 1088    collapse_matches: bool,
 1089    autoindent_mode: Option<AutoindentMode>,
 1090    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1091    input_enabled: bool,
 1092    use_modal_editing: bool,
 1093    read_only: bool,
 1094    leader_id: Option<CollaboratorId>,
 1095    remote_id: Option<ViewId>,
 1096    pub hover_state: HoverState,
 1097    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1098    gutter_hovered: bool,
 1099    hovered_link_state: Option<HoveredLinkState>,
 1100    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1101    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1102    active_edit_prediction: Option<EditPredictionState>,
 1103    /// Used to prevent flickering as the user types while the menu is open
 1104    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1105    edit_prediction_settings: EditPredictionSettings,
 1106    edit_predictions_hidden_for_vim_mode: bool,
 1107    show_edit_predictions_override: Option<bool>,
 1108    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1109    edit_prediction_preview: EditPredictionPreview,
 1110    edit_prediction_indent_conflict: bool,
 1111    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1112    inlay_hint_cache: InlayHintCache,
 1113    next_inlay_id: usize,
 1114    _subscriptions: Vec<Subscription>,
 1115    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1116    gutter_dimensions: GutterDimensions,
 1117    style: Option<EditorStyle>,
 1118    text_style_refinement: Option<TextStyleRefinement>,
 1119    next_editor_action_id: EditorActionId,
 1120    editor_actions: Rc<
 1121        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1122    >,
 1123    use_autoclose: bool,
 1124    use_auto_surround: bool,
 1125    auto_replace_emoji_shortcode: bool,
 1126    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1127    show_git_blame_gutter: bool,
 1128    show_git_blame_inline: bool,
 1129    show_git_blame_inline_delay_task: Option<Task<()>>,
 1130    git_blame_inline_enabled: bool,
 1131    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1132    serialize_dirty_buffers: bool,
 1133    show_selection_menu: Option<bool>,
 1134    blame: Option<Entity<GitBlame>>,
 1135    blame_subscription: Option<Subscription>,
 1136    custom_context_menu: Option<
 1137        Box<
 1138            dyn 'static
 1139                + Fn(
 1140                    &mut Self,
 1141                    DisplayPoint,
 1142                    &mut Window,
 1143                    &mut Context<Self>,
 1144                ) -> Option<Entity<ui::ContextMenu>>,
 1145        >,
 1146    >,
 1147    last_bounds: Option<Bounds<Pixels>>,
 1148    last_position_map: Option<Rc<PositionMap>>,
 1149    expect_bounds_change: Option<Bounds<Pixels>>,
 1150    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1151    tasks_update_task: Option<Task<()>>,
 1152    breakpoint_store: Option<Entity<BreakpointStore>>,
 1153    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1154    hovered_diff_hunk_row: Option<DisplayRow>,
 1155    pull_diagnostics_task: Task<()>,
 1156    in_project_search: bool,
 1157    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1158    breadcrumb_header: Option<String>,
 1159    focused_block: Option<FocusedBlock>,
 1160    next_scroll_position: NextScrollCursorCenterTopBottom,
 1161    addons: HashMap<TypeId, Box<dyn Addon>>,
 1162    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1163    load_diff_task: Option<Shared<Task<()>>>,
 1164    /// Whether we are temporarily displaying a diff other than git's
 1165    temporary_diff_override: bool,
 1166    selection_mark_mode: bool,
 1167    toggle_fold_multiple_buffers: Task<()>,
 1168    _scroll_cursor_center_top_bottom_task: Task<()>,
 1169    serialize_selections: Task<()>,
 1170    serialize_folds: Task<()>,
 1171    mouse_cursor_hidden: bool,
 1172    minimap: Option<Entity<Self>>,
 1173    hide_mouse_mode: HideMouseMode,
 1174    pub change_list: ChangeList,
 1175    inline_value_cache: InlineValueCache,
 1176    selection_drag_state: SelectionDragState,
 1177    next_color_inlay_id: usize,
 1178    colors: Option<LspColorData>,
 1179    folding_newlines: Task<()>,
 1180}
 1181
 1182#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1183enum NextScrollCursorCenterTopBottom {
 1184    #[default]
 1185    Center,
 1186    Top,
 1187    Bottom,
 1188}
 1189
 1190impl NextScrollCursorCenterTopBottom {
 1191    fn next(&self) -> Self {
 1192        match self {
 1193            Self::Center => Self::Top,
 1194            Self::Top => Self::Bottom,
 1195            Self::Bottom => Self::Center,
 1196        }
 1197    }
 1198}
 1199
 1200#[derive(Clone)]
 1201pub struct EditorSnapshot {
 1202    pub mode: EditorMode,
 1203    show_gutter: bool,
 1204    show_line_numbers: Option<bool>,
 1205    show_git_diff_gutter: Option<bool>,
 1206    show_code_actions: Option<bool>,
 1207    show_runnables: Option<bool>,
 1208    show_breakpoints: Option<bool>,
 1209    git_blame_gutter_max_author_length: Option<usize>,
 1210    pub display_snapshot: DisplaySnapshot,
 1211    pub placeholder_text: Option<Arc<str>>,
 1212    is_focused: bool,
 1213    scroll_anchor: ScrollAnchor,
 1214    ongoing_scroll: OngoingScroll,
 1215    current_line_highlight: CurrentLineHighlight,
 1216    gutter_hovered: bool,
 1217}
 1218
 1219#[derive(Default, Debug, Clone, Copy)]
 1220pub struct GutterDimensions {
 1221    pub left_padding: Pixels,
 1222    pub right_padding: Pixels,
 1223    pub width: Pixels,
 1224    pub margin: Pixels,
 1225    pub git_blame_entries_width: Option<Pixels>,
 1226}
 1227
 1228impl GutterDimensions {
 1229    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1230        Self {
 1231            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1232            ..Default::default()
 1233        }
 1234    }
 1235
 1236    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1237        -cx.text_system().descent(font_id, font_size)
 1238    }
 1239    /// The full width of the space taken up by the gutter.
 1240    pub fn full_width(&self) -> Pixels {
 1241        self.margin + self.width
 1242    }
 1243
 1244    /// The width of the space reserved for the fold indicators,
 1245    /// use alongside 'justify_end' and `gutter_width` to
 1246    /// right align content with the line numbers
 1247    pub fn fold_area_width(&self) -> Pixels {
 1248        self.margin + self.right_padding
 1249    }
 1250}
 1251
 1252struct CharacterDimensions {
 1253    em_width: Pixels,
 1254    em_advance: Pixels,
 1255    line_height: Pixels,
 1256}
 1257
 1258#[derive(Debug)]
 1259pub struct RemoteSelection {
 1260    pub replica_id: ReplicaId,
 1261    pub selection: Selection<Anchor>,
 1262    pub cursor_shape: CursorShape,
 1263    pub collaborator_id: CollaboratorId,
 1264    pub line_mode: bool,
 1265    pub user_name: Option<SharedString>,
 1266    pub color: PlayerColor,
 1267}
 1268
 1269#[derive(Clone, Debug)]
 1270struct SelectionHistoryEntry {
 1271    selections: Arc<[Selection<Anchor>]>,
 1272    select_next_state: Option<SelectNextState>,
 1273    select_prev_state: Option<SelectNextState>,
 1274    add_selections_state: Option<AddSelectionsState>,
 1275}
 1276
 1277#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1278enum SelectionHistoryMode {
 1279    Normal,
 1280    Undoing,
 1281    Redoing,
 1282    Skipping,
 1283}
 1284
 1285#[derive(Clone, PartialEq, Eq, Hash)]
 1286struct HoveredCursor {
 1287    replica_id: u16,
 1288    selection_id: usize,
 1289}
 1290
 1291impl Default for SelectionHistoryMode {
 1292    fn default() -> Self {
 1293        Self::Normal
 1294    }
 1295}
 1296
 1297#[derive(Debug)]
 1298/// SelectionEffects controls the side-effects of updating the selection.
 1299///
 1300/// The default behaviour does "what you mostly want":
 1301/// - it pushes to the nav history if the cursor moved by >10 lines
 1302/// - it re-triggers completion requests
 1303/// - it scrolls to fit
 1304///
 1305/// You might want to modify these behaviours. For example when doing a "jump"
 1306/// like go to definition, we always want to add to nav history; but when scrolling
 1307/// in vim mode we never do.
 1308///
 1309/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1310/// move.
 1311#[derive(Clone)]
 1312pub struct SelectionEffects {
 1313    nav_history: Option<bool>,
 1314    completions: bool,
 1315    scroll: Option<Autoscroll>,
 1316}
 1317
 1318impl Default for SelectionEffects {
 1319    fn default() -> Self {
 1320        Self {
 1321            nav_history: None,
 1322            completions: true,
 1323            scroll: Some(Autoscroll::fit()),
 1324        }
 1325    }
 1326}
 1327impl SelectionEffects {
 1328    pub fn scroll(scroll: Autoscroll) -> Self {
 1329        Self {
 1330            scroll: Some(scroll),
 1331            ..Default::default()
 1332        }
 1333    }
 1334
 1335    pub fn no_scroll() -> Self {
 1336        Self {
 1337            scroll: None,
 1338            ..Default::default()
 1339        }
 1340    }
 1341
 1342    pub fn completions(self, completions: bool) -> Self {
 1343        Self {
 1344            completions,
 1345            ..self
 1346        }
 1347    }
 1348
 1349    pub fn nav_history(self, nav_history: bool) -> Self {
 1350        Self {
 1351            nav_history: Some(nav_history),
 1352            ..self
 1353        }
 1354    }
 1355}
 1356
 1357struct DeferredSelectionEffectsState {
 1358    changed: bool,
 1359    effects: SelectionEffects,
 1360    old_cursor_position: Anchor,
 1361    history_entry: SelectionHistoryEntry,
 1362}
 1363
 1364#[derive(Default)]
 1365struct SelectionHistory {
 1366    #[allow(clippy::type_complexity)]
 1367    selections_by_transaction:
 1368        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1369    mode: SelectionHistoryMode,
 1370    undo_stack: VecDeque<SelectionHistoryEntry>,
 1371    redo_stack: VecDeque<SelectionHistoryEntry>,
 1372}
 1373
 1374impl SelectionHistory {
 1375    #[track_caller]
 1376    fn insert_transaction(
 1377        &mut self,
 1378        transaction_id: TransactionId,
 1379        selections: Arc<[Selection<Anchor>]>,
 1380    ) {
 1381        if selections.is_empty() {
 1382            log::error!(
 1383                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1384                std::panic::Location::caller()
 1385            );
 1386            return;
 1387        }
 1388        self.selections_by_transaction
 1389            .insert(transaction_id, (selections, None));
 1390    }
 1391
 1392    #[allow(clippy::type_complexity)]
 1393    fn transaction(
 1394        &self,
 1395        transaction_id: TransactionId,
 1396    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1397        self.selections_by_transaction.get(&transaction_id)
 1398    }
 1399
 1400    #[allow(clippy::type_complexity)]
 1401    fn transaction_mut(
 1402        &mut self,
 1403        transaction_id: TransactionId,
 1404    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1405        self.selections_by_transaction.get_mut(&transaction_id)
 1406    }
 1407
 1408    fn push(&mut self, entry: SelectionHistoryEntry) {
 1409        if !entry.selections.is_empty() {
 1410            match self.mode {
 1411                SelectionHistoryMode::Normal => {
 1412                    self.push_undo(entry);
 1413                    self.redo_stack.clear();
 1414                }
 1415                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1416                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1417                SelectionHistoryMode::Skipping => {}
 1418            }
 1419        }
 1420    }
 1421
 1422    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1423        if self
 1424            .undo_stack
 1425            .back()
 1426            .is_none_or(|e| e.selections != entry.selections)
 1427        {
 1428            self.undo_stack.push_back(entry);
 1429            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1430                self.undo_stack.pop_front();
 1431            }
 1432        }
 1433    }
 1434
 1435    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1436        if self
 1437            .redo_stack
 1438            .back()
 1439            .is_none_or(|e| e.selections != entry.selections)
 1440        {
 1441            self.redo_stack.push_back(entry);
 1442            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1443                self.redo_stack.pop_front();
 1444            }
 1445        }
 1446    }
 1447}
 1448
 1449#[derive(Clone, Copy)]
 1450pub struct RowHighlightOptions {
 1451    pub autoscroll: bool,
 1452    pub include_gutter: bool,
 1453}
 1454
 1455impl Default for RowHighlightOptions {
 1456    fn default() -> Self {
 1457        Self {
 1458            autoscroll: Default::default(),
 1459            include_gutter: true,
 1460        }
 1461    }
 1462}
 1463
 1464struct RowHighlight {
 1465    index: usize,
 1466    range: Range<Anchor>,
 1467    color: Hsla,
 1468    options: RowHighlightOptions,
 1469    type_id: TypeId,
 1470}
 1471
 1472#[derive(Clone, Debug)]
 1473struct AddSelectionsState {
 1474    groups: Vec<AddSelectionsGroup>,
 1475}
 1476
 1477#[derive(Clone, Debug)]
 1478struct AddSelectionsGroup {
 1479    above: bool,
 1480    stack: Vec<usize>,
 1481}
 1482
 1483#[derive(Clone)]
 1484struct SelectNextState {
 1485    query: AhoCorasick,
 1486    wordwise: bool,
 1487    done: bool,
 1488}
 1489
 1490impl std::fmt::Debug for SelectNextState {
 1491    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1492        f.debug_struct(std::any::type_name::<Self>())
 1493            .field("wordwise", &self.wordwise)
 1494            .field("done", &self.done)
 1495            .finish()
 1496    }
 1497}
 1498
 1499#[derive(Debug)]
 1500struct AutocloseRegion {
 1501    selection_id: usize,
 1502    range: Range<Anchor>,
 1503    pair: BracketPair,
 1504}
 1505
 1506#[derive(Debug)]
 1507struct SnippetState {
 1508    ranges: Vec<Vec<Range<Anchor>>>,
 1509    active_index: usize,
 1510    choices: Vec<Option<Vec<String>>>,
 1511}
 1512
 1513#[doc(hidden)]
 1514pub struct RenameState {
 1515    pub range: Range<Anchor>,
 1516    pub old_name: Arc<str>,
 1517    pub editor: Entity<Editor>,
 1518    block_id: CustomBlockId,
 1519}
 1520
 1521struct InvalidationStack<T>(Vec<T>);
 1522
 1523struct RegisteredEditPredictionProvider {
 1524    provider: Arc<dyn EditPredictionProviderHandle>,
 1525    _subscription: Subscription,
 1526}
 1527
 1528#[derive(Debug, PartialEq, Eq)]
 1529pub struct ActiveDiagnosticGroup {
 1530    pub active_range: Range<Anchor>,
 1531    pub active_message: String,
 1532    pub group_id: usize,
 1533    pub blocks: HashSet<CustomBlockId>,
 1534}
 1535
 1536#[derive(Debug, PartialEq, Eq)]
 1537
 1538pub(crate) enum ActiveDiagnostic {
 1539    None,
 1540    All,
 1541    Group(ActiveDiagnosticGroup),
 1542}
 1543
 1544#[derive(Serialize, Deserialize, Clone, Debug)]
 1545pub struct ClipboardSelection {
 1546    /// The number of bytes in this selection.
 1547    pub len: usize,
 1548    /// Whether this was a full-line selection.
 1549    pub is_entire_line: bool,
 1550    /// The indentation of the first line when this content was originally copied.
 1551    pub first_line_indent: u32,
 1552}
 1553
 1554// selections, scroll behavior, was newest selection reversed
 1555type SelectSyntaxNodeHistoryState = (
 1556    Box<[Selection<usize>]>,
 1557    SelectSyntaxNodeScrollBehavior,
 1558    bool,
 1559);
 1560
 1561#[derive(Default)]
 1562struct SelectSyntaxNodeHistory {
 1563    stack: Vec<SelectSyntaxNodeHistoryState>,
 1564    // disable temporarily to allow changing selections without losing the stack
 1565    pub disable_clearing: bool,
 1566}
 1567
 1568impl SelectSyntaxNodeHistory {
 1569    pub fn try_clear(&mut self) {
 1570        if !self.disable_clearing {
 1571            self.stack.clear();
 1572        }
 1573    }
 1574
 1575    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1576        self.stack.push(selection);
 1577    }
 1578
 1579    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1580        self.stack.pop()
 1581    }
 1582}
 1583
 1584enum SelectSyntaxNodeScrollBehavior {
 1585    CursorTop,
 1586    FitSelection,
 1587    CursorBottom,
 1588}
 1589
 1590#[derive(Debug)]
 1591pub(crate) struct NavigationData {
 1592    cursor_anchor: Anchor,
 1593    cursor_position: Point,
 1594    scroll_anchor: ScrollAnchor,
 1595    scroll_top_row: u32,
 1596}
 1597
 1598#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1599pub enum GotoDefinitionKind {
 1600    Symbol,
 1601    Declaration,
 1602    Type,
 1603    Implementation,
 1604}
 1605
 1606#[derive(Debug, Clone)]
 1607enum InlayHintRefreshReason {
 1608    ModifiersChanged(bool),
 1609    Toggle(bool),
 1610    SettingsChange(InlayHintSettings),
 1611    NewLinesShown,
 1612    BufferEdited(HashSet<Arc<Language>>),
 1613    RefreshRequested,
 1614    ExcerptsRemoved(Vec<ExcerptId>),
 1615}
 1616
 1617impl InlayHintRefreshReason {
 1618    fn description(&self) -> &'static str {
 1619        match self {
 1620            Self::ModifiersChanged(_) => "modifiers changed",
 1621            Self::Toggle(_) => "toggle",
 1622            Self::SettingsChange(_) => "settings change",
 1623            Self::NewLinesShown => "new lines shown",
 1624            Self::BufferEdited(_) => "buffer edited",
 1625            Self::RefreshRequested => "refresh requested",
 1626            Self::ExcerptsRemoved(_) => "excerpts removed",
 1627        }
 1628    }
 1629}
 1630
 1631pub enum FormatTarget {
 1632    Buffers(HashSet<Entity<Buffer>>),
 1633    Ranges(Vec<Range<MultiBufferPoint>>),
 1634}
 1635
 1636pub(crate) struct FocusedBlock {
 1637    id: BlockId,
 1638    focus_handle: WeakFocusHandle,
 1639}
 1640
 1641#[derive(Clone)]
 1642enum JumpData {
 1643    MultiBufferRow {
 1644        row: MultiBufferRow,
 1645        line_offset_from_top: u32,
 1646    },
 1647    MultiBufferPoint {
 1648        excerpt_id: ExcerptId,
 1649        position: Point,
 1650        anchor: text::Anchor,
 1651        line_offset_from_top: u32,
 1652    },
 1653}
 1654
 1655pub enum MultibufferSelectionMode {
 1656    First,
 1657    All,
 1658}
 1659
 1660#[derive(Clone, Copy, Debug, Default)]
 1661pub struct RewrapOptions {
 1662    pub override_language_settings: bool,
 1663    pub preserve_existing_whitespace: bool,
 1664}
 1665
 1666impl Editor {
 1667    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1668        let buffer = cx.new(|cx| Buffer::local("", cx));
 1669        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1670        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1671    }
 1672
 1673    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1674        let buffer = cx.new(|cx| Buffer::local("", cx));
 1675        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1676        Self::new(EditorMode::full(), buffer, None, window, cx)
 1677    }
 1678
 1679    pub fn auto_height(
 1680        min_lines: usize,
 1681        max_lines: usize,
 1682        window: &mut Window,
 1683        cx: &mut Context<Self>,
 1684    ) -> Self {
 1685        let buffer = cx.new(|cx| Buffer::local("", cx));
 1686        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1687        Self::new(
 1688            EditorMode::AutoHeight {
 1689                min_lines,
 1690                max_lines: Some(max_lines),
 1691            },
 1692            buffer,
 1693            None,
 1694            window,
 1695            cx,
 1696        )
 1697    }
 1698
 1699    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1700    /// The editor grows as tall as needed to fit its content.
 1701    pub fn auto_height_unbounded(
 1702        min_lines: usize,
 1703        window: &mut Window,
 1704        cx: &mut Context<Self>,
 1705    ) -> Self {
 1706        let buffer = cx.new(|cx| Buffer::local("", cx));
 1707        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1708        Self::new(
 1709            EditorMode::AutoHeight {
 1710                min_lines,
 1711                max_lines: None,
 1712            },
 1713            buffer,
 1714            None,
 1715            window,
 1716            cx,
 1717        )
 1718    }
 1719
 1720    pub fn for_buffer(
 1721        buffer: Entity<Buffer>,
 1722        project: Option<Entity<Project>>,
 1723        window: &mut Window,
 1724        cx: &mut Context<Self>,
 1725    ) -> Self {
 1726        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1727        Self::new(EditorMode::full(), buffer, project, window, cx)
 1728    }
 1729
 1730    pub fn for_multibuffer(
 1731        buffer: Entity<MultiBuffer>,
 1732        project: Option<Entity<Project>>,
 1733        window: &mut Window,
 1734        cx: &mut Context<Self>,
 1735    ) -> Self {
 1736        Self::new(EditorMode::full(), buffer, project, window, cx)
 1737    }
 1738
 1739    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1740        let mut clone = Self::new(
 1741            self.mode.clone(),
 1742            self.buffer.clone(),
 1743            self.project.clone(),
 1744            window,
 1745            cx,
 1746        );
 1747        self.display_map.update(cx, |display_map, cx| {
 1748            let snapshot = display_map.snapshot(cx);
 1749            clone.display_map.update(cx, |display_map, cx| {
 1750                display_map.set_state(&snapshot, cx);
 1751            });
 1752        });
 1753        clone.folds_did_change(cx);
 1754        clone.selections.clone_state(&self.selections);
 1755        clone.scroll_manager.clone_state(&self.scroll_manager);
 1756        clone.searchable = self.searchable;
 1757        clone.read_only = self.read_only;
 1758        clone
 1759    }
 1760
 1761    pub fn new(
 1762        mode: EditorMode,
 1763        buffer: Entity<MultiBuffer>,
 1764        project: Option<Entity<Project>>,
 1765        window: &mut Window,
 1766        cx: &mut Context<Self>,
 1767    ) -> Self {
 1768        Editor::new_internal(mode, buffer, project, None, window, cx)
 1769    }
 1770
 1771    fn new_internal(
 1772        mode: EditorMode,
 1773        buffer: Entity<MultiBuffer>,
 1774        project: Option<Entity<Project>>,
 1775        display_map: Option<Entity<DisplayMap>>,
 1776        window: &mut Window,
 1777        cx: &mut Context<Self>,
 1778    ) -> Self {
 1779        debug_assert!(
 1780            display_map.is_none() || mode.is_minimap(),
 1781            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1782        );
 1783
 1784        let full_mode = mode.is_full();
 1785        let is_minimap = mode.is_minimap();
 1786        let diagnostics_max_severity = if full_mode {
 1787            EditorSettings::get_global(cx)
 1788                .diagnostics_max_severity
 1789                .unwrap_or(DiagnosticSeverity::Hint)
 1790        } else {
 1791            DiagnosticSeverity::Off
 1792        };
 1793        let style = window.text_style();
 1794        let font_size = style.font_size.to_pixels(window.rem_size());
 1795        let editor = cx.entity().downgrade();
 1796        let fold_placeholder = FoldPlaceholder {
 1797            constrain_width: true,
 1798            render: Arc::new(move |fold_id, fold_range, cx| {
 1799                let editor = editor.clone();
 1800                div()
 1801                    .id(fold_id)
 1802                    .bg(cx.theme().colors().ghost_element_background)
 1803                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1804                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1805                    .rounded_xs()
 1806                    .size_full()
 1807                    .cursor_pointer()
 1808                    .child("")
 1809                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1810                    .on_click(move |_, _window, cx| {
 1811                        editor
 1812                            .update(cx, |editor, cx| {
 1813                                editor.unfold_ranges(
 1814                                    &[fold_range.start..fold_range.end],
 1815                                    true,
 1816                                    false,
 1817                                    cx,
 1818                                );
 1819                                cx.stop_propagation();
 1820                            })
 1821                            .ok();
 1822                    })
 1823                    .into_any()
 1824            }),
 1825            merge_adjacent: true,
 1826            ..FoldPlaceholder::default()
 1827        };
 1828        let display_map = display_map.unwrap_or_else(|| {
 1829            cx.new(|cx| {
 1830                DisplayMap::new(
 1831                    buffer.clone(),
 1832                    style.font(),
 1833                    font_size,
 1834                    None,
 1835                    FILE_HEADER_HEIGHT,
 1836                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1837                    fold_placeholder,
 1838                    diagnostics_max_severity,
 1839                    cx,
 1840                )
 1841            })
 1842        });
 1843
 1844        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1845
 1846        let blink_manager = cx.new(|cx| {
 1847            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1848            if is_minimap {
 1849                blink_manager.disable(cx);
 1850            }
 1851            blink_manager
 1852        });
 1853
 1854        let soft_wrap_mode_override =
 1855            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1856
 1857        let mut project_subscriptions = Vec::new();
 1858        if full_mode && let Some(project) = project.as_ref() {
 1859            project_subscriptions.push(cx.subscribe_in(
 1860                project,
 1861                window,
 1862                |editor, _, event, window, cx| match event {
 1863                    project::Event::RefreshCodeLens => {
 1864                        // we always query lens with actions, without storing them, always refreshing them
 1865                    }
 1866                    project::Event::RefreshInlayHints => {
 1867                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1868                    }
 1869                    project::Event::LanguageServerAdded(..)
 1870                    | project::Event::LanguageServerRemoved(..) => {
 1871                        if editor.tasks_update_task.is_none() {
 1872                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1873                        }
 1874                    }
 1875                    project::Event::SnippetEdit(id, snippet_edits) => {
 1876                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1877                            let focus_handle = editor.focus_handle(cx);
 1878                            if focus_handle.is_focused(window) {
 1879                                let snapshot = buffer.read(cx).snapshot();
 1880                                for (range, snippet) in snippet_edits {
 1881                                    let editor_range =
 1882                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1883                                    editor
 1884                                        .insert_snippet(
 1885                                            &[editor_range],
 1886                                            snippet.clone(),
 1887                                            window,
 1888                                            cx,
 1889                                        )
 1890                                        .ok();
 1891                                }
 1892                            }
 1893                        }
 1894                    }
 1895                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1896                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1897                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1898                        }
 1899                    }
 1900
 1901                    project::Event::EntryRenamed(transaction) => {
 1902                        let Some(workspace) = editor.workspace() else {
 1903                            return;
 1904                        };
 1905                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1906                        else {
 1907                            return;
 1908                        };
 1909                        if active_editor.entity_id() == cx.entity_id() {
 1910                            let edited_buffers_already_open = {
 1911                                let other_editors: Vec<Entity<Editor>> = workspace
 1912                                    .read(cx)
 1913                                    .panes()
 1914                                    .iter()
 1915                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1916                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1917                                    .collect();
 1918
 1919                                transaction.0.keys().all(|buffer| {
 1920                                    other_editors.iter().any(|editor| {
 1921                                        let multi_buffer = editor.read(cx).buffer();
 1922                                        multi_buffer.read(cx).is_singleton()
 1923                                            && multi_buffer.read(cx).as_singleton().map_or(
 1924                                                false,
 1925                                                |singleton| {
 1926                                                    singleton.entity_id() == buffer.entity_id()
 1927                                                },
 1928                                            )
 1929                                    })
 1930                                })
 1931                            };
 1932
 1933                            if !edited_buffers_already_open {
 1934                                let workspace = workspace.downgrade();
 1935                                let transaction = transaction.clone();
 1936                                cx.defer_in(window, move |_, window, cx| {
 1937                                    cx.spawn_in(window, async move |editor, cx| {
 1938                                        Self::open_project_transaction(
 1939                                            &editor,
 1940                                            workspace,
 1941                                            transaction,
 1942                                            "Rename".to_string(),
 1943                                            cx,
 1944                                        )
 1945                                        .await
 1946                                        .ok()
 1947                                    })
 1948                                    .detach();
 1949                                });
 1950                            }
 1951                        }
 1952                    }
 1953
 1954                    _ => {}
 1955                },
 1956            ));
 1957            if let Some(task_inventory) = project
 1958                .read(cx)
 1959                .task_store()
 1960                .read(cx)
 1961                .task_inventory()
 1962                .cloned()
 1963            {
 1964                project_subscriptions.push(cx.observe_in(
 1965                    &task_inventory,
 1966                    window,
 1967                    |editor, _, window, cx| {
 1968                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1969                    },
 1970                ));
 1971            };
 1972
 1973            project_subscriptions.push(cx.subscribe_in(
 1974                &project.read(cx).breakpoint_store(),
 1975                window,
 1976                |editor, _, event, window, cx| match event {
 1977                    BreakpointStoreEvent::ClearDebugLines => {
 1978                        editor.clear_row_highlights::<ActiveDebugLine>();
 1979                        editor.refresh_inline_values(cx);
 1980                    }
 1981                    BreakpointStoreEvent::SetDebugLine => {
 1982                        if editor.go_to_active_debug_line(window, cx) {
 1983                            cx.stop_propagation();
 1984                        }
 1985
 1986                        editor.refresh_inline_values(cx);
 1987                    }
 1988                    _ => {}
 1989                },
 1990            ));
 1991            let git_store = project.read(cx).git_store().clone();
 1992            let project = project.clone();
 1993            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1994                if let GitStoreEvent::RepositoryUpdated(
 1995                    _,
 1996                    RepositoryEvent::Updated {
 1997                        new_instance: true, ..
 1998                    },
 1999                    _,
 2000                ) = event
 2001                {
 2002                    this.load_diff_task = Some(
 2003                        update_uncommitted_diff_for_buffer(
 2004                            cx.entity(),
 2005                            &project,
 2006                            this.buffer.read(cx).all_buffers(),
 2007                            this.buffer.clone(),
 2008                            cx,
 2009                        )
 2010                        .shared(),
 2011                    );
 2012                }
 2013            }));
 2014        }
 2015
 2016        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2017
 2018        let inlay_hint_settings =
 2019            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2020        let focus_handle = cx.focus_handle();
 2021        if !is_minimap {
 2022            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2023                .detach();
 2024            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2025                .detach();
 2026            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2027                .detach();
 2028            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2029                .detach();
 2030            cx.observe_pending_input(window, Self::observe_pending_input)
 2031                .detach();
 2032        }
 2033
 2034        let show_indent_guides =
 2035            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2036                Some(false)
 2037            } else {
 2038                None
 2039            };
 2040
 2041        let breakpoint_store = match (&mode, project.as_ref()) {
 2042            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2043            _ => None,
 2044        };
 2045
 2046        let mut code_action_providers = Vec::new();
 2047        let mut load_uncommitted_diff = None;
 2048        if let Some(project) = project.clone() {
 2049            load_uncommitted_diff = Some(
 2050                update_uncommitted_diff_for_buffer(
 2051                    cx.entity(),
 2052                    &project,
 2053                    buffer.read(cx).all_buffers(),
 2054                    buffer.clone(),
 2055                    cx,
 2056                )
 2057                .shared(),
 2058            );
 2059            code_action_providers.push(Rc::new(project) as Rc<_>);
 2060        }
 2061
 2062        let mut editor = Self {
 2063            focus_handle,
 2064            show_cursor_when_unfocused: false,
 2065            last_focused_descendant: None,
 2066            buffer: buffer.clone(),
 2067            display_map: display_map.clone(),
 2068            selections,
 2069            scroll_manager: ScrollManager::new(cx),
 2070            columnar_selection_state: None,
 2071            add_selections_state: None,
 2072            select_next_state: None,
 2073            select_prev_state: None,
 2074            selection_history: SelectionHistory::default(),
 2075            defer_selection_effects: false,
 2076            deferred_selection_effects_state: None,
 2077            autoclose_regions: Vec::new(),
 2078            snippet_stack: InvalidationStack::default(),
 2079            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2080            ime_transaction: None,
 2081            active_diagnostics: ActiveDiagnostic::None,
 2082            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2083            inline_diagnostics_update: Task::ready(()),
 2084            inline_diagnostics: Vec::new(),
 2085            soft_wrap_mode_override,
 2086            diagnostics_max_severity,
 2087            hard_wrap: None,
 2088            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2089            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2090            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2091            project,
 2092            blink_manager: blink_manager.clone(),
 2093            show_local_selections: true,
 2094            show_scrollbars: ScrollbarAxes {
 2095                horizontal: full_mode,
 2096                vertical: full_mode,
 2097            },
 2098            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2099            offset_content: !matches!(mode, EditorMode::SingleLine),
 2100            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2101            show_gutter: full_mode,
 2102            show_line_numbers: (!full_mode).then_some(false),
 2103            use_relative_line_numbers: None,
 2104            disable_expand_excerpt_buttons: !full_mode,
 2105            show_git_diff_gutter: None,
 2106            show_code_actions: None,
 2107            show_runnables: None,
 2108            show_breakpoints: None,
 2109            show_wrap_guides: None,
 2110            show_indent_guides,
 2111            placeholder_text: None,
 2112            highlight_order: 0,
 2113            highlighted_rows: HashMap::default(),
 2114            background_highlights: TreeMap::default(),
 2115            gutter_highlights: TreeMap::default(),
 2116            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2117            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2118            nav_history: None,
 2119            context_menu: RefCell::new(None),
 2120            context_menu_options: None,
 2121            mouse_context_menu: None,
 2122            completion_tasks: Vec::new(),
 2123            inline_blame_popover: None,
 2124            inline_blame_popover_show_task: None,
 2125            signature_help_state: SignatureHelpState::default(),
 2126            auto_signature_help: None,
 2127            find_all_references_task_sources: Vec::new(),
 2128            next_completion_id: 0,
 2129            next_inlay_id: 0,
 2130            code_action_providers,
 2131            available_code_actions: None,
 2132            code_actions_task: None,
 2133            quick_selection_highlight_task: None,
 2134            debounced_selection_highlight_task: None,
 2135            document_highlights_task: None,
 2136            linked_editing_range_task: None,
 2137            pending_rename: None,
 2138            searchable: !is_minimap,
 2139            cursor_shape: EditorSettings::get_global(cx)
 2140                .cursor_shape
 2141                .unwrap_or_default(),
 2142            current_line_highlight: None,
 2143            autoindent_mode: Some(AutoindentMode::EachLine),
 2144            collapse_matches: false,
 2145            workspace: None,
 2146            input_enabled: !is_minimap,
 2147            use_modal_editing: full_mode,
 2148            read_only: is_minimap,
 2149            use_autoclose: true,
 2150            use_auto_surround: true,
 2151            auto_replace_emoji_shortcode: false,
 2152            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2153            leader_id: None,
 2154            remote_id: None,
 2155            hover_state: HoverState::default(),
 2156            pending_mouse_down: None,
 2157            hovered_link_state: None,
 2158            edit_prediction_provider: None,
 2159            active_edit_prediction: None,
 2160            stale_edit_prediction_in_menu: None,
 2161            edit_prediction_preview: EditPredictionPreview::Inactive {
 2162                released_too_fast: false,
 2163            },
 2164            inline_diagnostics_enabled: full_mode,
 2165            diagnostics_enabled: full_mode,
 2166            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2167            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2168            gutter_hovered: false,
 2169            pixel_position_of_newest_cursor: None,
 2170            last_bounds: None,
 2171            last_position_map: None,
 2172            expect_bounds_change: None,
 2173            gutter_dimensions: GutterDimensions::default(),
 2174            style: None,
 2175            show_cursor_names: false,
 2176            hovered_cursors: HashMap::default(),
 2177            next_editor_action_id: EditorActionId::default(),
 2178            editor_actions: Rc::default(),
 2179            edit_predictions_hidden_for_vim_mode: false,
 2180            show_edit_predictions_override: None,
 2181            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2182            edit_prediction_settings: EditPredictionSettings::Disabled,
 2183            edit_prediction_indent_conflict: false,
 2184            edit_prediction_requires_modifier_in_indent_conflict: true,
 2185            custom_context_menu: None,
 2186            show_git_blame_gutter: false,
 2187            show_git_blame_inline: false,
 2188            show_selection_menu: None,
 2189            show_git_blame_inline_delay_task: None,
 2190            git_blame_inline_enabled: full_mode
 2191                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2192            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2193            serialize_dirty_buffers: !is_minimap
 2194                && ProjectSettings::get_global(cx)
 2195                    .session
 2196                    .restore_unsaved_buffers,
 2197            blame: None,
 2198            blame_subscription: None,
 2199            tasks: BTreeMap::default(),
 2200
 2201            breakpoint_store,
 2202            gutter_breakpoint_indicator: (None, None),
 2203            hovered_diff_hunk_row: None,
 2204            _subscriptions: (!is_minimap)
 2205                .then(|| {
 2206                    vec![
 2207                        cx.observe(&buffer, Self::on_buffer_changed),
 2208                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2209                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2210                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2211                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2212                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2213                        cx.observe_window_activation(window, |editor, window, cx| {
 2214                            let active = window.is_window_active();
 2215                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2216                                if active {
 2217                                    blink_manager.enable(cx);
 2218                                } else {
 2219                                    blink_manager.disable(cx);
 2220                                }
 2221                            });
 2222                            if active {
 2223                                editor.show_mouse_cursor(cx);
 2224                            }
 2225                        }),
 2226                    ]
 2227                })
 2228                .unwrap_or_default(),
 2229            tasks_update_task: None,
 2230            pull_diagnostics_task: Task::ready(()),
 2231            colors: None,
 2232            next_color_inlay_id: 0,
 2233            linked_edit_ranges: Default::default(),
 2234            in_project_search: false,
 2235            previous_search_ranges: None,
 2236            breadcrumb_header: None,
 2237            focused_block: None,
 2238            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2239            addons: HashMap::default(),
 2240            registered_buffers: HashMap::default(),
 2241            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2242            selection_mark_mode: false,
 2243            toggle_fold_multiple_buffers: Task::ready(()),
 2244            serialize_selections: Task::ready(()),
 2245            serialize_folds: Task::ready(()),
 2246            text_style_refinement: None,
 2247            load_diff_task: load_uncommitted_diff,
 2248            temporary_diff_override: false,
 2249            mouse_cursor_hidden: false,
 2250            minimap: None,
 2251            hide_mouse_mode: EditorSettings::get_global(cx)
 2252                .hide_mouse
 2253                .unwrap_or_default(),
 2254            change_list: ChangeList::new(),
 2255            mode,
 2256            selection_drag_state: SelectionDragState::None,
 2257            folding_newlines: Task::ready(()),
 2258        };
 2259
 2260        if is_minimap {
 2261            return editor;
 2262        }
 2263
 2264        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2265            editor
 2266                ._subscriptions
 2267                .push(cx.observe(breakpoints, |_, _, cx| {
 2268                    cx.notify();
 2269                }));
 2270        }
 2271        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2272        editor._subscriptions.extend(project_subscriptions);
 2273
 2274        editor._subscriptions.push(cx.subscribe_in(
 2275            &cx.entity(),
 2276            window,
 2277            |editor, _, e: &EditorEvent, window, cx| match e {
 2278                EditorEvent::ScrollPositionChanged { local, .. } => {
 2279                    if *local {
 2280                        let new_anchor = editor.scroll_manager.anchor();
 2281                        let snapshot = editor.snapshot(window, cx);
 2282                        editor.update_restoration_data(cx, move |data| {
 2283                            data.scroll_position = (
 2284                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2285                                new_anchor.offset,
 2286                            );
 2287                        });
 2288                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2289                        editor.inline_blame_popover.take();
 2290                    }
 2291                }
 2292                EditorEvent::Edited { .. } => {
 2293                    if !vim_enabled(cx) {
 2294                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2295                        let pop_state = editor
 2296                            .change_list
 2297                            .last()
 2298                            .map(|previous| {
 2299                                previous.len() == selections.len()
 2300                                    && previous.iter().enumerate().all(|(ix, p)| {
 2301                                        p.to_display_point(&map).row()
 2302                                            == selections[ix].head().row()
 2303                                    })
 2304                            })
 2305                            .unwrap_or(false);
 2306                        let new_positions = selections
 2307                            .into_iter()
 2308                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2309                            .collect();
 2310                        editor
 2311                            .change_list
 2312                            .push_to_change_list(pop_state, new_positions);
 2313                    }
 2314                }
 2315                _ => (),
 2316            },
 2317        ));
 2318
 2319        if let Some(dap_store) = editor
 2320            .project
 2321            .as_ref()
 2322            .map(|project| project.read(cx).dap_store())
 2323        {
 2324            let weak_editor = cx.weak_entity();
 2325
 2326            editor
 2327                ._subscriptions
 2328                .push(
 2329                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2330                        let session_entity = cx.entity();
 2331                        weak_editor
 2332                            .update(cx, |editor, cx| {
 2333                                editor._subscriptions.push(
 2334                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2335                                );
 2336                            })
 2337                            .ok();
 2338                    }),
 2339                );
 2340
 2341            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2342                editor
 2343                    ._subscriptions
 2344                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2345            }
 2346        }
 2347
 2348        // skip adding the initial selection to selection history
 2349        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2350        editor.end_selection(window, cx);
 2351        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2352
 2353        editor.scroll_manager.show_scrollbars(window, cx);
 2354        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2355
 2356        if full_mode {
 2357            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2358            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2359
 2360            if editor.git_blame_inline_enabled {
 2361                editor.start_git_blame_inline(false, window, cx);
 2362            }
 2363
 2364            editor.go_to_active_debug_line(window, cx);
 2365
 2366            if let Some(buffer) = buffer.read(cx).as_singleton()
 2367                && let Some(project) = editor.project()
 2368            {
 2369                let handle = project.update(cx, |project, cx| {
 2370                    project.register_buffer_with_language_servers(&buffer, cx)
 2371                });
 2372                editor
 2373                    .registered_buffers
 2374                    .insert(buffer.read(cx).remote_id(), handle);
 2375            }
 2376
 2377            editor.minimap =
 2378                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2379            editor.colors = Some(LspColorData::new(cx));
 2380            editor.update_lsp_data(false, None, window, cx);
 2381        }
 2382
 2383        if editor.mode.is_full() {
 2384            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2385        }
 2386
 2387        editor
 2388    }
 2389
 2390    pub fn deploy_mouse_context_menu(
 2391        &mut self,
 2392        position: gpui::Point<Pixels>,
 2393        context_menu: Entity<ContextMenu>,
 2394        window: &mut Window,
 2395        cx: &mut Context<Self>,
 2396    ) {
 2397        self.mouse_context_menu = Some(MouseContextMenu::new(
 2398            self,
 2399            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2400            context_menu,
 2401            window,
 2402            cx,
 2403        ));
 2404    }
 2405
 2406    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2407        self.mouse_context_menu
 2408            .as_ref()
 2409            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2410    }
 2411
 2412    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2413        if self
 2414            .selections
 2415            .pending
 2416            .as_ref()
 2417            .is_some_and(|pending_selection| {
 2418                let snapshot = self.buffer().read(cx).snapshot(cx);
 2419                pending_selection
 2420                    .selection
 2421                    .range()
 2422                    .includes(range, &snapshot)
 2423            })
 2424        {
 2425            return true;
 2426        }
 2427
 2428        self.selections
 2429            .disjoint_in_range::<usize>(range.clone(), cx)
 2430            .into_iter()
 2431            .any(|selection| {
 2432                // This is needed to cover a corner case, if we just check for an existing
 2433                // selection in the fold range, having a cursor at the start of the fold
 2434                // marks it as selected. Non-empty selections don't cause this.
 2435                let length = selection.end - selection.start;
 2436                length > 0
 2437            })
 2438    }
 2439
 2440    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2441        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2442    }
 2443
 2444    fn key_context_internal(
 2445        &self,
 2446        has_active_edit_prediction: bool,
 2447        window: &Window,
 2448        cx: &App,
 2449    ) -> KeyContext {
 2450        let mut key_context = KeyContext::new_with_defaults();
 2451        key_context.add("Editor");
 2452        let mode = match self.mode {
 2453            EditorMode::SingleLine => "single_line",
 2454            EditorMode::AutoHeight { .. } => "auto_height",
 2455            EditorMode::Minimap { .. } => "minimap",
 2456            EditorMode::Full { .. } => "full",
 2457        };
 2458
 2459        if EditorSettings::jupyter_enabled(cx) {
 2460            key_context.add("jupyter");
 2461        }
 2462
 2463        key_context.set("mode", mode);
 2464        if self.pending_rename.is_some() {
 2465            key_context.add("renaming");
 2466        }
 2467
 2468        match self.context_menu.borrow().as_ref() {
 2469            Some(CodeContextMenu::Completions(menu)) => {
 2470                if menu.visible() {
 2471                    key_context.add("menu");
 2472                    key_context.add("showing_completions");
 2473                }
 2474            }
 2475            Some(CodeContextMenu::CodeActions(menu)) => {
 2476                if menu.visible() {
 2477                    key_context.add("menu");
 2478                    key_context.add("showing_code_actions")
 2479                }
 2480            }
 2481            None => {}
 2482        }
 2483
 2484        if self.signature_help_state.has_multiple_signatures() {
 2485            key_context.add("showing_signature_help");
 2486        }
 2487
 2488        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2489        if !self.focus_handle(cx).contains_focused(window, cx)
 2490            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2491        {
 2492            for addon in self.addons.values() {
 2493                addon.extend_key_context(&mut key_context, cx)
 2494            }
 2495        }
 2496
 2497        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2498            if let Some(extension) = singleton_buffer
 2499                .read(cx)
 2500                .file()
 2501                .and_then(|file| file.path().extension()?.to_str())
 2502            {
 2503                key_context.set("extension", extension.to_string());
 2504            }
 2505        } else {
 2506            key_context.add("multibuffer");
 2507        }
 2508
 2509        if has_active_edit_prediction {
 2510            if self.edit_prediction_in_conflict() {
 2511                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2512            } else {
 2513                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2514                key_context.add("copilot_suggestion");
 2515            }
 2516        }
 2517
 2518        if self.selection_mark_mode {
 2519            key_context.add("selection_mode");
 2520        }
 2521
 2522        key_context
 2523    }
 2524
 2525    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2526        if self.mouse_cursor_hidden {
 2527            self.mouse_cursor_hidden = false;
 2528            cx.notify();
 2529        }
 2530    }
 2531
 2532    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2533        let hide_mouse_cursor = match origin {
 2534            HideMouseCursorOrigin::TypingAction => {
 2535                matches!(
 2536                    self.hide_mouse_mode,
 2537                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2538                )
 2539            }
 2540            HideMouseCursorOrigin::MovementAction => {
 2541                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2542            }
 2543        };
 2544        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2545            self.mouse_cursor_hidden = hide_mouse_cursor;
 2546            cx.notify();
 2547        }
 2548    }
 2549
 2550    pub fn edit_prediction_in_conflict(&self) -> bool {
 2551        if !self.show_edit_predictions_in_menu() {
 2552            return false;
 2553        }
 2554
 2555        let showing_completions = self
 2556            .context_menu
 2557            .borrow()
 2558            .as_ref()
 2559            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2560
 2561        showing_completions
 2562            || self.edit_prediction_requires_modifier()
 2563            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2564            // bindings to insert tab characters.
 2565            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2566    }
 2567
 2568    pub fn accept_edit_prediction_keybind(
 2569        &self,
 2570        accept_partial: bool,
 2571        window: &Window,
 2572        cx: &App,
 2573    ) -> AcceptEditPredictionBinding {
 2574        let key_context = self.key_context_internal(true, window, cx);
 2575        let in_conflict = self.edit_prediction_in_conflict();
 2576
 2577        let bindings = if accept_partial {
 2578            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2579        } else {
 2580            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2581        };
 2582
 2583        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2584        // just the first one.
 2585        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2586            !in_conflict
 2587                || binding
 2588                    .keystrokes()
 2589                    .first()
 2590                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2591        }))
 2592    }
 2593
 2594    pub fn new_file(
 2595        workspace: &mut Workspace,
 2596        _: &workspace::NewFile,
 2597        window: &mut Window,
 2598        cx: &mut Context<Workspace>,
 2599    ) {
 2600        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2601            "Failed to create buffer",
 2602            window,
 2603            cx,
 2604            |e, _, _| match e.error_code() {
 2605                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2606                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2607                e.error_tag("required").unwrap_or("the latest version")
 2608            )),
 2609                _ => None,
 2610            },
 2611        );
 2612    }
 2613
 2614    pub fn new_in_workspace(
 2615        workspace: &mut Workspace,
 2616        window: &mut Window,
 2617        cx: &mut Context<Workspace>,
 2618    ) -> Task<Result<Entity<Editor>>> {
 2619        let project = workspace.project().clone();
 2620        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2621
 2622        cx.spawn_in(window, async move |workspace, cx| {
 2623            let buffer = create.await?;
 2624            workspace.update_in(cx, |workspace, window, cx| {
 2625                let editor =
 2626                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2627                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2628                editor
 2629            })
 2630        })
 2631    }
 2632
 2633    fn new_file_vertical(
 2634        workspace: &mut Workspace,
 2635        _: &workspace::NewFileSplitVertical,
 2636        window: &mut Window,
 2637        cx: &mut Context<Workspace>,
 2638    ) {
 2639        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2640    }
 2641
 2642    fn new_file_horizontal(
 2643        workspace: &mut Workspace,
 2644        _: &workspace::NewFileSplitHorizontal,
 2645        window: &mut Window,
 2646        cx: &mut Context<Workspace>,
 2647    ) {
 2648        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2649    }
 2650
 2651    fn new_file_in_direction(
 2652        workspace: &mut Workspace,
 2653        direction: SplitDirection,
 2654        window: &mut Window,
 2655        cx: &mut Context<Workspace>,
 2656    ) {
 2657        let project = workspace.project().clone();
 2658        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2659
 2660        cx.spawn_in(window, async move |workspace, cx| {
 2661            let buffer = create.await?;
 2662            workspace.update_in(cx, move |workspace, window, cx| {
 2663                workspace.split_item(
 2664                    direction,
 2665                    Box::new(
 2666                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2667                    ),
 2668                    window,
 2669                    cx,
 2670                )
 2671            })?;
 2672            anyhow::Ok(())
 2673        })
 2674        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2675            match e.error_code() {
 2676                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2677                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2678                e.error_tag("required").unwrap_or("the latest version")
 2679            )),
 2680                _ => None,
 2681            }
 2682        });
 2683    }
 2684
 2685    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2686        self.leader_id
 2687    }
 2688
 2689    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2690        &self.buffer
 2691    }
 2692
 2693    pub fn project(&self) -> Option<&Entity<Project>> {
 2694        self.project.as_ref()
 2695    }
 2696
 2697    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2698        self.workspace.as_ref()?.0.upgrade()
 2699    }
 2700
 2701    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2702        self.buffer().read(cx).title(cx)
 2703    }
 2704
 2705    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2706        let git_blame_gutter_max_author_length = self
 2707            .render_git_blame_gutter(cx)
 2708            .then(|| {
 2709                if let Some(blame) = self.blame.as_ref() {
 2710                    let max_author_length =
 2711                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2712                    Some(max_author_length)
 2713                } else {
 2714                    None
 2715                }
 2716            })
 2717            .flatten();
 2718
 2719        EditorSnapshot {
 2720            mode: self.mode.clone(),
 2721            show_gutter: self.show_gutter,
 2722            show_line_numbers: self.show_line_numbers,
 2723            show_git_diff_gutter: self.show_git_diff_gutter,
 2724            show_code_actions: self.show_code_actions,
 2725            show_runnables: self.show_runnables,
 2726            show_breakpoints: self.show_breakpoints,
 2727            git_blame_gutter_max_author_length,
 2728            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2729            scroll_anchor: self.scroll_manager.anchor(),
 2730            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2731            placeholder_text: self.placeholder_text.clone(),
 2732            is_focused: self.focus_handle.is_focused(window),
 2733            current_line_highlight: self
 2734                .current_line_highlight
 2735                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2736            gutter_hovered: self.gutter_hovered,
 2737        }
 2738    }
 2739
 2740    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2741        self.buffer.read(cx).language_at(point, cx)
 2742    }
 2743
 2744    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2745        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2746    }
 2747
 2748    pub fn active_excerpt(
 2749        &self,
 2750        cx: &App,
 2751    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2752        self.buffer
 2753            .read(cx)
 2754            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2755    }
 2756
 2757    pub fn mode(&self) -> &EditorMode {
 2758        &self.mode
 2759    }
 2760
 2761    pub fn set_mode(&mut self, mode: EditorMode) {
 2762        self.mode = mode;
 2763    }
 2764
 2765    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2766        self.collaboration_hub.as_deref()
 2767    }
 2768
 2769    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2770        self.collaboration_hub = Some(hub);
 2771    }
 2772
 2773    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2774        self.in_project_search = in_project_search;
 2775    }
 2776
 2777    pub fn set_custom_context_menu(
 2778        &mut self,
 2779        f: impl 'static
 2780        + Fn(
 2781            &mut Self,
 2782            DisplayPoint,
 2783            &mut Window,
 2784            &mut Context<Self>,
 2785        ) -> Option<Entity<ui::ContextMenu>>,
 2786    ) {
 2787        self.custom_context_menu = Some(Box::new(f))
 2788    }
 2789
 2790    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2791        self.completion_provider = provider;
 2792    }
 2793
 2794    #[cfg(any(test, feature = "test-support"))]
 2795    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2796        self.completion_provider.clone()
 2797    }
 2798
 2799    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2800        self.semantics_provider.clone()
 2801    }
 2802
 2803    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2804        self.semantics_provider = provider;
 2805    }
 2806
 2807    pub fn set_edit_prediction_provider<T>(
 2808        &mut self,
 2809        provider: Option<Entity<T>>,
 2810        window: &mut Window,
 2811        cx: &mut Context<Self>,
 2812    ) where
 2813        T: EditPredictionProvider,
 2814    {
 2815        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2816            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2817                if this.focus_handle.is_focused(window) {
 2818                    this.update_visible_edit_prediction(window, cx);
 2819                }
 2820            }),
 2821            provider: Arc::new(provider),
 2822        });
 2823        self.update_edit_prediction_settings(cx);
 2824        self.refresh_edit_prediction(false, false, window, cx);
 2825    }
 2826
 2827    pub fn placeholder_text(&self) -> Option<&str> {
 2828        self.placeholder_text.as_deref()
 2829    }
 2830
 2831    pub fn set_placeholder_text(
 2832        &mut self,
 2833        placeholder_text: impl Into<Arc<str>>,
 2834        cx: &mut Context<Self>,
 2835    ) {
 2836        let placeholder_text = Some(placeholder_text.into());
 2837        if self.placeholder_text != placeholder_text {
 2838            self.placeholder_text = placeholder_text;
 2839            cx.notify();
 2840        }
 2841    }
 2842
 2843    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2844        self.cursor_shape = cursor_shape;
 2845
 2846        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2847        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2848
 2849        cx.notify();
 2850    }
 2851
 2852    pub fn set_current_line_highlight(
 2853        &mut self,
 2854        current_line_highlight: Option<CurrentLineHighlight>,
 2855    ) {
 2856        self.current_line_highlight = current_line_highlight;
 2857    }
 2858
 2859    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2860        self.collapse_matches = collapse_matches;
 2861    }
 2862
 2863    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2864        let buffers = self.buffer.read(cx).all_buffers();
 2865        let Some(project) = self.project.as_ref() else {
 2866            return;
 2867        };
 2868        project.update(cx, |project, cx| {
 2869            for buffer in buffers {
 2870                self.registered_buffers
 2871                    .entry(buffer.read(cx).remote_id())
 2872                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2873            }
 2874        })
 2875    }
 2876
 2877    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2878        if self.collapse_matches {
 2879            return range.start..range.start;
 2880        }
 2881        range.clone()
 2882    }
 2883
 2884    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2885        if self.display_map.read(cx).clip_at_line_ends != clip {
 2886            self.display_map
 2887                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2888        }
 2889    }
 2890
 2891    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2892        self.input_enabled = input_enabled;
 2893    }
 2894
 2895    pub fn set_edit_predictions_hidden_for_vim_mode(
 2896        &mut self,
 2897        hidden: bool,
 2898        window: &mut Window,
 2899        cx: &mut Context<Self>,
 2900    ) {
 2901        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2902            self.edit_predictions_hidden_for_vim_mode = hidden;
 2903            if hidden {
 2904                self.update_visible_edit_prediction(window, cx);
 2905            } else {
 2906                self.refresh_edit_prediction(true, false, window, cx);
 2907            }
 2908        }
 2909    }
 2910
 2911    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2912        self.menu_edit_predictions_policy = value;
 2913    }
 2914
 2915    pub fn set_autoindent(&mut self, autoindent: bool) {
 2916        if autoindent {
 2917            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2918        } else {
 2919            self.autoindent_mode = None;
 2920        }
 2921    }
 2922
 2923    pub fn read_only(&self, cx: &App) -> bool {
 2924        self.read_only || self.buffer.read(cx).read_only()
 2925    }
 2926
 2927    pub fn set_read_only(&mut self, read_only: bool) {
 2928        self.read_only = read_only;
 2929    }
 2930
 2931    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2932        self.use_autoclose = autoclose;
 2933    }
 2934
 2935    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2936        self.use_auto_surround = auto_surround;
 2937    }
 2938
 2939    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2940        self.auto_replace_emoji_shortcode = auto_replace;
 2941    }
 2942
 2943    pub fn toggle_edit_predictions(
 2944        &mut self,
 2945        _: &ToggleEditPrediction,
 2946        window: &mut Window,
 2947        cx: &mut Context<Self>,
 2948    ) {
 2949        if self.show_edit_predictions_override.is_some() {
 2950            self.set_show_edit_predictions(None, window, cx);
 2951        } else {
 2952            let show_edit_predictions = !self.edit_predictions_enabled();
 2953            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2954        }
 2955    }
 2956
 2957    pub fn set_show_edit_predictions(
 2958        &mut self,
 2959        show_edit_predictions: Option<bool>,
 2960        window: &mut Window,
 2961        cx: &mut Context<Self>,
 2962    ) {
 2963        self.show_edit_predictions_override = show_edit_predictions;
 2964        self.update_edit_prediction_settings(cx);
 2965
 2966        if let Some(false) = show_edit_predictions {
 2967            self.discard_edit_prediction(false, cx);
 2968        } else {
 2969            self.refresh_edit_prediction(false, true, window, cx);
 2970        }
 2971    }
 2972
 2973    fn edit_predictions_disabled_in_scope(
 2974        &self,
 2975        buffer: &Entity<Buffer>,
 2976        buffer_position: language::Anchor,
 2977        cx: &App,
 2978    ) -> bool {
 2979        let snapshot = buffer.read(cx).snapshot();
 2980        let settings = snapshot.settings_at(buffer_position, cx);
 2981
 2982        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2983            return false;
 2984        };
 2985
 2986        scope.override_name().is_some_and(|scope_name| {
 2987            settings
 2988                .edit_predictions_disabled_in
 2989                .iter()
 2990                .any(|s| s == scope_name)
 2991        })
 2992    }
 2993
 2994    pub fn set_use_modal_editing(&mut self, to: bool) {
 2995        self.use_modal_editing = to;
 2996    }
 2997
 2998    pub fn use_modal_editing(&self) -> bool {
 2999        self.use_modal_editing
 3000    }
 3001
 3002    fn selections_did_change(
 3003        &mut self,
 3004        local: bool,
 3005        old_cursor_position: &Anchor,
 3006        effects: SelectionEffects,
 3007        window: &mut Window,
 3008        cx: &mut Context<Self>,
 3009    ) {
 3010        window.invalidate_character_coordinates();
 3011
 3012        // Copy selections to primary selection buffer
 3013        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3014        if local {
 3015            let selections = self.selections.all::<usize>(cx);
 3016            let buffer_handle = self.buffer.read(cx).read(cx);
 3017
 3018            let mut text = String::new();
 3019            for (index, selection) in selections.iter().enumerate() {
 3020                let text_for_selection = buffer_handle
 3021                    .text_for_range(selection.start..selection.end)
 3022                    .collect::<String>();
 3023
 3024                text.push_str(&text_for_selection);
 3025                if index != selections.len() - 1 {
 3026                    text.push('\n');
 3027                }
 3028            }
 3029
 3030            if !text.is_empty() {
 3031                cx.write_to_primary(ClipboardItem::new_string(text));
 3032            }
 3033        }
 3034
 3035        let selection_anchors = self.selections.disjoint_anchors();
 3036
 3037        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3038            self.buffer.update(cx, |buffer, cx| {
 3039                buffer.set_active_selections(
 3040                    &selection_anchors,
 3041                    self.selections.line_mode,
 3042                    self.cursor_shape,
 3043                    cx,
 3044                )
 3045            });
 3046        }
 3047        let display_map = self
 3048            .display_map
 3049            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3050        let buffer = &display_map.buffer_snapshot;
 3051        if self.selections.count() == 1 {
 3052            self.add_selections_state = None;
 3053        }
 3054        self.select_next_state = None;
 3055        self.select_prev_state = None;
 3056        self.select_syntax_node_history.try_clear();
 3057        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3058        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3059        self.take_rename(false, window, cx);
 3060
 3061        let newest_selection = self.selections.newest_anchor();
 3062        let new_cursor_position = newest_selection.head();
 3063        let selection_start = newest_selection.start;
 3064
 3065        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3066            self.push_to_nav_history(
 3067                *old_cursor_position,
 3068                Some(new_cursor_position.to_point(buffer)),
 3069                false,
 3070                effects.nav_history == Some(true),
 3071                cx,
 3072            );
 3073        }
 3074
 3075        if local {
 3076            if let Some(buffer_id) = new_cursor_position.buffer_id
 3077                && !self.registered_buffers.contains_key(&buffer_id)
 3078                && let Some(project) = self.project.as_ref()
 3079            {
 3080                project.update(cx, |project, cx| {
 3081                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3082                        return;
 3083                    };
 3084                    self.registered_buffers.insert(
 3085                        buffer_id,
 3086                        project.register_buffer_with_language_servers(&buffer, cx),
 3087                    );
 3088                })
 3089            }
 3090
 3091            let mut context_menu = self.context_menu.borrow_mut();
 3092            let completion_menu = match context_menu.as_ref() {
 3093                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3094                Some(CodeContextMenu::CodeActions(_)) => {
 3095                    *context_menu = None;
 3096                    None
 3097                }
 3098                None => None,
 3099            };
 3100            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3101            drop(context_menu);
 3102
 3103            if effects.completions
 3104                && let Some(completion_position) = completion_position
 3105            {
 3106                let start_offset = selection_start.to_offset(buffer);
 3107                let position_matches = start_offset == completion_position.to_offset(buffer);
 3108                let continue_showing = if position_matches {
 3109                    if self.snippet_stack.is_empty() {
 3110                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3111                    } else {
 3112                        // Snippet choices can be shown even when the cursor is in whitespace.
 3113                        // Dismissing the menu with actions like backspace is handled by
 3114                        // invalidation regions.
 3115                        true
 3116                    }
 3117                } else {
 3118                    false
 3119                };
 3120
 3121                if continue_showing {
 3122                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3123                } else {
 3124                    self.hide_context_menu(window, cx);
 3125                }
 3126            }
 3127
 3128            hide_hover(self, cx);
 3129
 3130            if old_cursor_position.to_display_point(&display_map).row()
 3131                != new_cursor_position.to_display_point(&display_map).row()
 3132            {
 3133                self.available_code_actions.take();
 3134            }
 3135            self.refresh_code_actions(window, cx);
 3136            self.refresh_document_highlights(cx);
 3137            self.refresh_selected_text_highlights(false, window, cx);
 3138            refresh_matching_bracket_highlights(self, window, cx);
 3139            self.update_visible_edit_prediction(window, cx);
 3140            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3141            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3142            self.inline_blame_popover.take();
 3143            if self.git_blame_inline_enabled {
 3144                self.start_inline_blame_timer(window, cx);
 3145            }
 3146        }
 3147
 3148        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3149        cx.emit(EditorEvent::SelectionsChanged { local });
 3150
 3151        let selections = &self.selections.disjoint;
 3152        if selections.len() == 1 {
 3153            cx.emit(SearchEvent::ActiveMatchChanged)
 3154        }
 3155        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3156            let inmemory_selections = selections
 3157                .iter()
 3158                .map(|s| {
 3159                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3160                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3161                })
 3162                .collect();
 3163            self.update_restoration_data(cx, |data| {
 3164                data.selections = inmemory_selections;
 3165            });
 3166
 3167            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3168                && let Some(workspace_id) =
 3169                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3170            {
 3171                let snapshot = self.buffer().read(cx).snapshot(cx);
 3172                let selections = selections.clone();
 3173                let background_executor = cx.background_executor().clone();
 3174                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3175                self.serialize_selections = cx.background_spawn(async move {
 3176                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3177                            let db_selections = selections
 3178                                .iter()
 3179                                .map(|selection| {
 3180                                    (
 3181                                        selection.start.to_offset(&snapshot),
 3182                                        selection.end.to_offset(&snapshot),
 3183                                    )
 3184                                })
 3185                                .collect();
 3186
 3187                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3188                                .await
 3189                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3190                                .log_err();
 3191                        });
 3192            }
 3193        }
 3194
 3195        cx.notify();
 3196    }
 3197
 3198    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3199        use text::ToOffset as _;
 3200        use text::ToPoint as _;
 3201
 3202        if self.mode.is_minimap()
 3203            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3204        {
 3205            return;
 3206        }
 3207
 3208        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3209            return;
 3210        };
 3211
 3212        let snapshot = singleton.read(cx).snapshot();
 3213        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3214            let display_snapshot = display_map.snapshot(cx);
 3215
 3216            display_snapshot
 3217                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3218                .map(|fold| {
 3219                    fold.range.start.text_anchor.to_point(&snapshot)
 3220                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3221                })
 3222                .collect()
 3223        });
 3224        self.update_restoration_data(cx, |data| {
 3225            data.folds = inmemory_folds;
 3226        });
 3227
 3228        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3229            return;
 3230        };
 3231        let background_executor = cx.background_executor().clone();
 3232        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3233        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3234            display_map
 3235                .snapshot(cx)
 3236                .folds_in_range(0..snapshot.len())
 3237                .map(|fold| {
 3238                    (
 3239                        fold.range.start.text_anchor.to_offset(&snapshot),
 3240                        fold.range.end.text_anchor.to_offset(&snapshot),
 3241                    )
 3242                })
 3243                .collect()
 3244        });
 3245        self.serialize_folds = cx.background_spawn(async move {
 3246            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3247            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3248                .await
 3249                .with_context(|| {
 3250                    format!(
 3251                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3252                    )
 3253                })
 3254                .log_err();
 3255        });
 3256    }
 3257
 3258    pub fn sync_selections(
 3259        &mut self,
 3260        other: Entity<Editor>,
 3261        cx: &mut Context<Self>,
 3262    ) -> gpui::Subscription {
 3263        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3264        self.selections.change_with(cx, |selections| {
 3265            selections.select_anchors(other_selections);
 3266        });
 3267
 3268        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3269            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3270                let other_selections = other.read(cx).selections.disjoint.to_vec();
 3271                if other_selections.is_empty() {
 3272                    return;
 3273                }
 3274                this.selections.change_with(cx, |selections| {
 3275                    selections.select_anchors(other_selections);
 3276                });
 3277            }
 3278        });
 3279
 3280        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3281            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3282                let these_selections = this.selections.disjoint.to_vec();
 3283                if these_selections.is_empty() {
 3284                    return;
 3285                }
 3286                other.update(cx, |other_editor, cx| {
 3287                    other_editor.selections.change_with(cx, |selections| {
 3288                        selections.select_anchors(these_selections);
 3289                    })
 3290                });
 3291            }
 3292        });
 3293
 3294        Subscription::join(other_subscription, this_subscription)
 3295    }
 3296
 3297    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3298    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3299    /// effects of selection change occur at the end of the transaction.
 3300    pub fn change_selections<R>(
 3301        &mut self,
 3302        effects: SelectionEffects,
 3303        window: &mut Window,
 3304        cx: &mut Context<Self>,
 3305        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3306    ) -> R {
 3307        if let Some(state) = &mut self.deferred_selection_effects_state {
 3308            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3309            state.effects.completions = effects.completions;
 3310            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3311            let (changed, result) = self.selections.change_with(cx, change);
 3312            state.changed |= changed;
 3313            return result;
 3314        }
 3315        let mut state = DeferredSelectionEffectsState {
 3316            changed: false,
 3317            effects,
 3318            old_cursor_position: self.selections.newest_anchor().head(),
 3319            history_entry: SelectionHistoryEntry {
 3320                selections: self.selections.disjoint_anchors(),
 3321                select_next_state: self.select_next_state.clone(),
 3322                select_prev_state: self.select_prev_state.clone(),
 3323                add_selections_state: self.add_selections_state.clone(),
 3324            },
 3325        };
 3326        let (changed, result) = self.selections.change_with(cx, change);
 3327        state.changed = state.changed || changed;
 3328        if self.defer_selection_effects {
 3329            self.deferred_selection_effects_state = Some(state);
 3330        } else {
 3331            self.apply_selection_effects(state, window, cx);
 3332        }
 3333        result
 3334    }
 3335
 3336    /// Defers the effects of selection change, so that the effects of multiple calls to
 3337    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3338    /// to selection history and the state of popovers based on selection position aren't
 3339    /// erroneously updated.
 3340    pub fn with_selection_effects_deferred<R>(
 3341        &mut self,
 3342        window: &mut Window,
 3343        cx: &mut Context<Self>,
 3344        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3345    ) -> R {
 3346        let already_deferred = self.defer_selection_effects;
 3347        self.defer_selection_effects = true;
 3348        let result = update(self, window, cx);
 3349        if !already_deferred {
 3350            self.defer_selection_effects = false;
 3351            if let Some(state) = self.deferred_selection_effects_state.take() {
 3352                self.apply_selection_effects(state, window, cx);
 3353            }
 3354        }
 3355        result
 3356    }
 3357
 3358    fn apply_selection_effects(
 3359        &mut self,
 3360        state: DeferredSelectionEffectsState,
 3361        window: &mut Window,
 3362        cx: &mut Context<Self>,
 3363    ) {
 3364        if state.changed {
 3365            self.selection_history.push(state.history_entry);
 3366
 3367            if let Some(autoscroll) = state.effects.scroll {
 3368                self.request_autoscroll(autoscroll, cx);
 3369            }
 3370
 3371            let old_cursor_position = &state.old_cursor_position;
 3372
 3373            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3374
 3375            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3376                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3377            }
 3378        }
 3379    }
 3380
 3381    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3382    where
 3383        I: IntoIterator<Item = (Range<S>, T)>,
 3384        S: ToOffset,
 3385        T: Into<Arc<str>>,
 3386    {
 3387        if self.read_only(cx) {
 3388            return;
 3389        }
 3390
 3391        self.buffer
 3392            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3393    }
 3394
 3395    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3396    where
 3397        I: IntoIterator<Item = (Range<S>, T)>,
 3398        S: ToOffset,
 3399        T: Into<Arc<str>>,
 3400    {
 3401        if self.read_only(cx) {
 3402            return;
 3403        }
 3404
 3405        self.buffer.update(cx, |buffer, cx| {
 3406            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3407        });
 3408    }
 3409
 3410    pub fn edit_with_block_indent<I, S, T>(
 3411        &mut self,
 3412        edits: I,
 3413        original_indent_columns: Vec<Option<u32>>,
 3414        cx: &mut Context<Self>,
 3415    ) where
 3416        I: IntoIterator<Item = (Range<S>, T)>,
 3417        S: ToOffset,
 3418        T: Into<Arc<str>>,
 3419    {
 3420        if self.read_only(cx) {
 3421            return;
 3422        }
 3423
 3424        self.buffer.update(cx, |buffer, cx| {
 3425            buffer.edit(
 3426                edits,
 3427                Some(AutoindentMode::Block {
 3428                    original_indent_columns,
 3429                }),
 3430                cx,
 3431            )
 3432        });
 3433    }
 3434
 3435    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3436        self.hide_context_menu(window, cx);
 3437
 3438        match phase {
 3439            SelectPhase::Begin {
 3440                position,
 3441                add,
 3442                click_count,
 3443            } => self.begin_selection(position, add, click_count, window, cx),
 3444            SelectPhase::BeginColumnar {
 3445                position,
 3446                goal_column,
 3447                reset,
 3448                mode,
 3449            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3450            SelectPhase::Extend {
 3451                position,
 3452                click_count,
 3453            } => self.extend_selection(position, click_count, window, cx),
 3454            SelectPhase::Update {
 3455                position,
 3456                goal_column,
 3457                scroll_delta,
 3458            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3459            SelectPhase::End => self.end_selection(window, cx),
 3460        }
 3461    }
 3462
 3463    fn extend_selection(
 3464        &mut self,
 3465        position: DisplayPoint,
 3466        click_count: usize,
 3467        window: &mut Window,
 3468        cx: &mut Context<Self>,
 3469    ) {
 3470        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3471        let tail = self.selections.newest::<usize>(cx).tail();
 3472        self.begin_selection(position, false, click_count, window, cx);
 3473
 3474        let position = position.to_offset(&display_map, Bias::Left);
 3475        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3476
 3477        let mut pending_selection = self
 3478            .selections
 3479            .pending_anchor()
 3480            .expect("extend_selection not called with pending selection");
 3481        if position >= tail {
 3482            pending_selection.start = tail_anchor;
 3483        } else {
 3484            pending_selection.end = tail_anchor;
 3485            pending_selection.reversed = true;
 3486        }
 3487
 3488        let mut pending_mode = self.selections.pending_mode().unwrap();
 3489        match &mut pending_mode {
 3490            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3491            _ => {}
 3492        }
 3493
 3494        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3495            SelectionEffects::scroll(Autoscroll::fit())
 3496        } else {
 3497            SelectionEffects::no_scroll()
 3498        };
 3499
 3500        self.change_selections(effects, window, cx, |s| {
 3501            s.set_pending(pending_selection, pending_mode)
 3502        });
 3503    }
 3504
 3505    fn begin_selection(
 3506        &mut self,
 3507        position: DisplayPoint,
 3508        add: bool,
 3509        click_count: usize,
 3510        window: &mut Window,
 3511        cx: &mut Context<Self>,
 3512    ) {
 3513        if !self.focus_handle.is_focused(window) {
 3514            self.last_focused_descendant = None;
 3515            window.focus(&self.focus_handle);
 3516        }
 3517
 3518        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3519        let buffer = &display_map.buffer_snapshot;
 3520        let position = display_map.clip_point(position, Bias::Left);
 3521
 3522        let start;
 3523        let end;
 3524        let mode;
 3525        let mut auto_scroll;
 3526        match click_count {
 3527            1 => {
 3528                start = buffer.anchor_before(position.to_point(&display_map));
 3529                end = start;
 3530                mode = SelectMode::Character;
 3531                auto_scroll = true;
 3532            }
 3533            2 => {
 3534                let position = display_map
 3535                    .clip_point(position, Bias::Left)
 3536                    .to_offset(&display_map, Bias::Left);
 3537                let (range, _) = buffer.surrounding_word(position, false);
 3538                start = buffer.anchor_before(range.start);
 3539                end = buffer.anchor_before(range.end);
 3540                mode = SelectMode::Word(start..end);
 3541                auto_scroll = true;
 3542            }
 3543            3 => {
 3544                let position = display_map
 3545                    .clip_point(position, Bias::Left)
 3546                    .to_point(&display_map);
 3547                let line_start = display_map.prev_line_boundary(position).0;
 3548                let next_line_start = buffer.clip_point(
 3549                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3550                    Bias::Left,
 3551                );
 3552                start = buffer.anchor_before(line_start);
 3553                end = buffer.anchor_before(next_line_start);
 3554                mode = SelectMode::Line(start..end);
 3555                auto_scroll = true;
 3556            }
 3557            _ => {
 3558                start = buffer.anchor_before(0);
 3559                end = buffer.anchor_before(buffer.len());
 3560                mode = SelectMode::All;
 3561                auto_scroll = false;
 3562            }
 3563        }
 3564        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3565
 3566        let point_to_delete: Option<usize> = {
 3567            let selected_points: Vec<Selection<Point>> =
 3568                self.selections.disjoint_in_range(start..end, cx);
 3569
 3570            if !add || click_count > 1 {
 3571                None
 3572            } else if !selected_points.is_empty() {
 3573                Some(selected_points[0].id)
 3574            } else {
 3575                let clicked_point_already_selected =
 3576                    self.selections.disjoint.iter().find(|selection| {
 3577                        selection.start.to_point(buffer) == start.to_point(buffer)
 3578                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3579                    });
 3580
 3581                clicked_point_already_selected.map(|selection| selection.id)
 3582            }
 3583        };
 3584
 3585        let selections_count = self.selections.count();
 3586        let effects = if auto_scroll {
 3587            SelectionEffects::default()
 3588        } else {
 3589            SelectionEffects::no_scroll()
 3590        };
 3591
 3592        self.change_selections(effects, window, cx, |s| {
 3593            if let Some(point_to_delete) = point_to_delete {
 3594                s.delete(point_to_delete);
 3595
 3596                if selections_count == 1 {
 3597                    s.set_pending_anchor_range(start..end, mode);
 3598                }
 3599            } else {
 3600                if !add {
 3601                    s.clear_disjoint();
 3602                }
 3603
 3604                s.set_pending_anchor_range(start..end, mode);
 3605            }
 3606        });
 3607    }
 3608
 3609    fn begin_columnar_selection(
 3610        &mut self,
 3611        position: DisplayPoint,
 3612        goal_column: u32,
 3613        reset: bool,
 3614        mode: ColumnarMode,
 3615        window: &mut Window,
 3616        cx: &mut Context<Self>,
 3617    ) {
 3618        if !self.focus_handle.is_focused(window) {
 3619            self.last_focused_descendant = None;
 3620            window.focus(&self.focus_handle);
 3621        }
 3622
 3623        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3624
 3625        if reset {
 3626            let pointer_position = display_map
 3627                .buffer_snapshot
 3628                .anchor_before(position.to_point(&display_map));
 3629
 3630            self.change_selections(
 3631                SelectionEffects::scroll(Autoscroll::newest()),
 3632                window,
 3633                cx,
 3634                |s| {
 3635                    s.clear_disjoint();
 3636                    s.set_pending_anchor_range(
 3637                        pointer_position..pointer_position,
 3638                        SelectMode::Character,
 3639                    );
 3640                },
 3641            );
 3642        };
 3643
 3644        let tail = self.selections.newest::<Point>(cx).tail();
 3645        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3646        self.columnar_selection_state = match mode {
 3647            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3648                selection_tail: selection_anchor,
 3649                display_point: if reset {
 3650                    if position.column() != goal_column {
 3651                        Some(DisplayPoint::new(position.row(), goal_column))
 3652                    } else {
 3653                        None
 3654                    }
 3655                } else {
 3656                    None
 3657                },
 3658            }),
 3659            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3660                selection_tail: selection_anchor,
 3661            }),
 3662        };
 3663
 3664        if !reset {
 3665            self.select_columns(position, goal_column, &display_map, window, cx);
 3666        }
 3667    }
 3668
 3669    fn update_selection(
 3670        &mut self,
 3671        position: DisplayPoint,
 3672        goal_column: u32,
 3673        scroll_delta: gpui::Point<f32>,
 3674        window: &mut Window,
 3675        cx: &mut Context<Self>,
 3676    ) {
 3677        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3678
 3679        if self.columnar_selection_state.is_some() {
 3680            self.select_columns(position, goal_column, &display_map, window, cx);
 3681        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3682            let buffer = &display_map.buffer_snapshot;
 3683            let head;
 3684            let tail;
 3685            let mode = self.selections.pending_mode().unwrap();
 3686            match &mode {
 3687                SelectMode::Character => {
 3688                    head = position.to_point(&display_map);
 3689                    tail = pending.tail().to_point(buffer);
 3690                }
 3691                SelectMode::Word(original_range) => {
 3692                    let offset = display_map
 3693                        .clip_point(position, Bias::Left)
 3694                        .to_offset(&display_map, Bias::Left);
 3695                    let original_range = original_range.to_offset(buffer);
 3696
 3697                    let head_offset = if buffer.is_inside_word(offset, false)
 3698                        || original_range.contains(&offset)
 3699                    {
 3700                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3701                        if word_range.start < original_range.start {
 3702                            word_range.start
 3703                        } else {
 3704                            word_range.end
 3705                        }
 3706                    } else {
 3707                        offset
 3708                    };
 3709
 3710                    head = head_offset.to_point(buffer);
 3711                    if head_offset <= original_range.start {
 3712                        tail = original_range.end.to_point(buffer);
 3713                    } else {
 3714                        tail = original_range.start.to_point(buffer);
 3715                    }
 3716                }
 3717                SelectMode::Line(original_range) => {
 3718                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3719
 3720                    let position = display_map
 3721                        .clip_point(position, Bias::Left)
 3722                        .to_point(&display_map);
 3723                    let line_start = display_map.prev_line_boundary(position).0;
 3724                    let next_line_start = buffer.clip_point(
 3725                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3726                        Bias::Left,
 3727                    );
 3728
 3729                    if line_start < original_range.start {
 3730                        head = line_start
 3731                    } else {
 3732                        head = next_line_start
 3733                    }
 3734
 3735                    if head <= original_range.start {
 3736                        tail = original_range.end;
 3737                    } else {
 3738                        tail = original_range.start;
 3739                    }
 3740                }
 3741                SelectMode::All => {
 3742                    return;
 3743                }
 3744            };
 3745
 3746            if head < tail {
 3747                pending.start = buffer.anchor_before(head);
 3748                pending.end = buffer.anchor_before(tail);
 3749                pending.reversed = true;
 3750            } else {
 3751                pending.start = buffer.anchor_before(tail);
 3752                pending.end = buffer.anchor_before(head);
 3753                pending.reversed = false;
 3754            }
 3755
 3756            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3757                s.set_pending(pending, mode);
 3758            });
 3759        } else {
 3760            log::error!("update_selection dispatched with no pending selection");
 3761            return;
 3762        }
 3763
 3764        self.apply_scroll_delta(scroll_delta, window, cx);
 3765        cx.notify();
 3766    }
 3767
 3768    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3769        self.columnar_selection_state.take();
 3770        if self.selections.pending_anchor().is_some() {
 3771            let selections = self.selections.all::<usize>(cx);
 3772            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3773                s.select(selections);
 3774                s.clear_pending();
 3775            });
 3776        }
 3777    }
 3778
 3779    fn select_columns(
 3780        &mut self,
 3781        head: DisplayPoint,
 3782        goal_column: u32,
 3783        display_map: &DisplaySnapshot,
 3784        window: &mut Window,
 3785        cx: &mut Context<Self>,
 3786    ) {
 3787        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3788            return;
 3789        };
 3790
 3791        let tail = match columnar_state {
 3792            ColumnarSelectionState::FromMouse {
 3793                selection_tail,
 3794                display_point,
 3795            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3796            ColumnarSelectionState::FromSelection { selection_tail } => {
 3797                selection_tail.to_display_point(display_map)
 3798            }
 3799        };
 3800
 3801        let start_row = cmp::min(tail.row(), head.row());
 3802        let end_row = cmp::max(tail.row(), head.row());
 3803        let start_column = cmp::min(tail.column(), goal_column);
 3804        let end_column = cmp::max(tail.column(), goal_column);
 3805        let reversed = start_column < tail.column();
 3806
 3807        let selection_ranges = (start_row.0..=end_row.0)
 3808            .map(DisplayRow)
 3809            .filter_map(|row| {
 3810                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3811                    || start_column <= display_map.line_len(row))
 3812                    && !display_map.is_block_line(row)
 3813                {
 3814                    let start = display_map
 3815                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3816                        .to_point(display_map);
 3817                    let end = display_map
 3818                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3819                        .to_point(display_map);
 3820                    if reversed {
 3821                        Some(end..start)
 3822                    } else {
 3823                        Some(start..end)
 3824                    }
 3825                } else {
 3826                    None
 3827                }
 3828            })
 3829            .collect::<Vec<_>>();
 3830
 3831        let ranges = match columnar_state {
 3832            ColumnarSelectionState::FromMouse { .. } => {
 3833                let mut non_empty_ranges = selection_ranges
 3834                    .iter()
 3835                    .filter(|selection_range| selection_range.start != selection_range.end)
 3836                    .peekable();
 3837                if non_empty_ranges.peek().is_some() {
 3838                    non_empty_ranges.cloned().collect()
 3839                } else {
 3840                    selection_ranges
 3841                }
 3842            }
 3843            _ => selection_ranges,
 3844        };
 3845
 3846        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3847            s.select_ranges(ranges);
 3848        });
 3849        cx.notify();
 3850    }
 3851
 3852    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3853        self.selections
 3854            .all_adjusted(cx)
 3855            .iter()
 3856            .any(|selection| !selection.is_empty())
 3857    }
 3858
 3859    pub fn has_pending_nonempty_selection(&self) -> bool {
 3860        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3861            Some(Selection { start, end, .. }) => start != end,
 3862            None => false,
 3863        };
 3864
 3865        pending_nonempty_selection
 3866            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3867    }
 3868
 3869    pub fn has_pending_selection(&self) -> bool {
 3870        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3871    }
 3872
 3873    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3874        self.selection_mark_mode = false;
 3875        self.selection_drag_state = SelectionDragState::None;
 3876
 3877        if self.clear_expanded_diff_hunks(cx) {
 3878            cx.notify();
 3879            return;
 3880        }
 3881        if self.dismiss_menus_and_popups(true, window, cx) {
 3882            return;
 3883        }
 3884
 3885        if self.mode.is_full()
 3886            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3887        {
 3888            return;
 3889        }
 3890
 3891        cx.propagate();
 3892    }
 3893
 3894    pub fn dismiss_menus_and_popups(
 3895        &mut self,
 3896        is_user_requested: bool,
 3897        window: &mut Window,
 3898        cx: &mut Context<Self>,
 3899    ) -> bool {
 3900        if self.take_rename(false, window, cx).is_some() {
 3901            return true;
 3902        }
 3903
 3904        if hide_hover(self, cx) {
 3905            return true;
 3906        }
 3907
 3908        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3909            return true;
 3910        }
 3911
 3912        if self.hide_context_menu(window, cx).is_some() {
 3913            return true;
 3914        }
 3915
 3916        if self.mouse_context_menu.take().is_some() {
 3917            return true;
 3918        }
 3919
 3920        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3921            return true;
 3922        }
 3923
 3924        if self.snippet_stack.pop().is_some() {
 3925            return true;
 3926        }
 3927
 3928        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3929            self.dismiss_diagnostics(cx);
 3930            return true;
 3931        }
 3932
 3933        false
 3934    }
 3935
 3936    fn linked_editing_ranges_for(
 3937        &self,
 3938        selection: Range<text::Anchor>,
 3939        cx: &App,
 3940    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3941        if self.linked_edit_ranges.is_empty() {
 3942            return None;
 3943        }
 3944        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3945            selection.end.buffer_id.and_then(|end_buffer_id| {
 3946                if selection.start.buffer_id != Some(end_buffer_id) {
 3947                    return None;
 3948                }
 3949                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3950                let snapshot = buffer.read(cx).snapshot();
 3951                self.linked_edit_ranges
 3952                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3953                    .map(|ranges| (ranges, snapshot, buffer))
 3954            })?;
 3955        use text::ToOffset as TO;
 3956        // find offset from the start of current range to current cursor position
 3957        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3958
 3959        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3960        let start_difference = start_offset - start_byte_offset;
 3961        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3962        let end_difference = end_offset - start_byte_offset;
 3963        // Current range has associated linked ranges.
 3964        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3965        for range in linked_ranges.iter() {
 3966            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3967            let end_offset = start_offset + end_difference;
 3968            let start_offset = start_offset + start_difference;
 3969            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3970                continue;
 3971            }
 3972            if self.selections.disjoint_anchor_ranges().any(|s| {
 3973                if s.start.buffer_id != selection.start.buffer_id
 3974                    || s.end.buffer_id != selection.end.buffer_id
 3975                {
 3976                    return false;
 3977                }
 3978                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3979                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3980            }) {
 3981                continue;
 3982            }
 3983            let start = buffer_snapshot.anchor_after(start_offset);
 3984            let end = buffer_snapshot.anchor_after(end_offset);
 3985            linked_edits
 3986                .entry(buffer.clone())
 3987                .or_default()
 3988                .push(start..end);
 3989        }
 3990        Some(linked_edits)
 3991    }
 3992
 3993    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3994        let text: Arc<str> = text.into();
 3995
 3996        if self.read_only(cx) {
 3997            return;
 3998        }
 3999
 4000        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4001
 4002        let selections = self.selections.all_adjusted(cx);
 4003        let mut bracket_inserted = false;
 4004        let mut edits = Vec::new();
 4005        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4006        let mut new_selections = Vec::with_capacity(selections.len());
 4007        let mut new_autoclose_regions = Vec::new();
 4008        let snapshot = self.buffer.read(cx).read(cx);
 4009        let mut clear_linked_edit_ranges = false;
 4010
 4011        for (selection, autoclose_region) in
 4012            self.selections_with_autoclose_regions(selections, &snapshot)
 4013        {
 4014            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4015                // Determine if the inserted text matches the opening or closing
 4016                // bracket of any of this language's bracket pairs.
 4017                let mut bracket_pair = None;
 4018                let mut is_bracket_pair_start = false;
 4019                let mut is_bracket_pair_end = false;
 4020                if !text.is_empty() {
 4021                    let mut bracket_pair_matching_end = None;
 4022                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4023                    //  and they are removing the character that triggered IME popup.
 4024                    for (pair, enabled) in scope.brackets() {
 4025                        if !pair.close && !pair.surround {
 4026                            continue;
 4027                        }
 4028
 4029                        if enabled && pair.start.ends_with(text.as_ref()) {
 4030                            let prefix_len = pair.start.len() - text.len();
 4031                            let preceding_text_matches_prefix = prefix_len == 0
 4032                                || (selection.start.column >= (prefix_len as u32)
 4033                                    && snapshot.contains_str_at(
 4034                                        Point::new(
 4035                                            selection.start.row,
 4036                                            selection.start.column - (prefix_len as u32),
 4037                                        ),
 4038                                        &pair.start[..prefix_len],
 4039                                    ));
 4040                            if preceding_text_matches_prefix {
 4041                                bracket_pair = Some(pair.clone());
 4042                                is_bracket_pair_start = true;
 4043                                break;
 4044                            }
 4045                        }
 4046                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4047                        {
 4048                            // take first bracket pair matching end, but don't break in case a later bracket
 4049                            // pair matches start
 4050                            bracket_pair_matching_end = Some(pair.clone());
 4051                        }
 4052                    }
 4053                    if let Some(end) = bracket_pair_matching_end
 4054                        && bracket_pair.is_none()
 4055                    {
 4056                        bracket_pair = Some(end);
 4057                        is_bracket_pair_end = true;
 4058                    }
 4059                }
 4060
 4061                if let Some(bracket_pair) = bracket_pair {
 4062                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4063                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4064                    let auto_surround =
 4065                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4066                    if selection.is_empty() {
 4067                        if is_bracket_pair_start {
 4068                            // If the inserted text is a suffix of an opening bracket and the
 4069                            // selection is preceded by the rest of the opening bracket, then
 4070                            // insert the closing bracket.
 4071                            let following_text_allows_autoclose = snapshot
 4072                                .chars_at(selection.start)
 4073                                .next()
 4074                                .is_none_or(|c| scope.should_autoclose_before(c));
 4075
 4076                            let preceding_text_allows_autoclose = selection.start.column == 0
 4077                                || snapshot
 4078                                    .reversed_chars_at(selection.start)
 4079                                    .next()
 4080                                    .is_none_or(|c| {
 4081                                        bracket_pair.start != bracket_pair.end
 4082                                            || !snapshot
 4083                                                .char_classifier_at(selection.start)
 4084                                                .is_word(c)
 4085                                    });
 4086
 4087                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4088                                && bracket_pair.start.len() == 1
 4089                            {
 4090                                let target = bracket_pair.start.chars().next().unwrap();
 4091                                let current_line_count = snapshot
 4092                                    .reversed_chars_at(selection.start)
 4093                                    .take_while(|&c| c != '\n')
 4094                                    .filter(|&c| c == target)
 4095                                    .count();
 4096                                current_line_count % 2 == 1
 4097                            } else {
 4098                                false
 4099                            };
 4100
 4101                            if autoclose
 4102                                && bracket_pair.close
 4103                                && following_text_allows_autoclose
 4104                                && preceding_text_allows_autoclose
 4105                                && !is_closing_quote
 4106                            {
 4107                                let anchor = snapshot.anchor_before(selection.end);
 4108                                new_selections.push((selection.map(|_| anchor), text.len()));
 4109                                new_autoclose_regions.push((
 4110                                    anchor,
 4111                                    text.len(),
 4112                                    selection.id,
 4113                                    bracket_pair.clone(),
 4114                                ));
 4115                                edits.push((
 4116                                    selection.range(),
 4117                                    format!("{}{}", text, bracket_pair.end).into(),
 4118                                ));
 4119                                bracket_inserted = true;
 4120                                continue;
 4121                            }
 4122                        }
 4123
 4124                        if let Some(region) = autoclose_region {
 4125                            // If the selection is followed by an auto-inserted closing bracket,
 4126                            // then don't insert that closing bracket again; just move the selection
 4127                            // past the closing bracket.
 4128                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4129                                && text.as_ref() == region.pair.end.as_str()
 4130                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4131                            if should_skip {
 4132                                let anchor = snapshot.anchor_after(selection.end);
 4133                                new_selections
 4134                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4135                                continue;
 4136                            }
 4137                        }
 4138
 4139                        let always_treat_brackets_as_autoclosed = snapshot
 4140                            .language_settings_at(selection.start, cx)
 4141                            .always_treat_brackets_as_autoclosed;
 4142                        if always_treat_brackets_as_autoclosed
 4143                            && is_bracket_pair_end
 4144                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4145                        {
 4146                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4147                            // and the inserted text is a closing bracket and the selection is followed
 4148                            // by the closing bracket then move the selection past the closing bracket.
 4149                            let anchor = snapshot.anchor_after(selection.end);
 4150                            new_selections.push((selection.map(|_| anchor), text.len()));
 4151                            continue;
 4152                        }
 4153                    }
 4154                    // If an opening bracket is 1 character long and is typed while
 4155                    // text is selected, then surround that text with the bracket pair.
 4156                    else if auto_surround
 4157                        && bracket_pair.surround
 4158                        && is_bracket_pair_start
 4159                        && bracket_pair.start.chars().count() == 1
 4160                    {
 4161                        edits.push((selection.start..selection.start, text.clone()));
 4162                        edits.push((
 4163                            selection.end..selection.end,
 4164                            bracket_pair.end.as_str().into(),
 4165                        ));
 4166                        bracket_inserted = true;
 4167                        new_selections.push((
 4168                            Selection {
 4169                                id: selection.id,
 4170                                start: snapshot.anchor_after(selection.start),
 4171                                end: snapshot.anchor_before(selection.end),
 4172                                reversed: selection.reversed,
 4173                                goal: selection.goal,
 4174                            },
 4175                            0,
 4176                        ));
 4177                        continue;
 4178                    }
 4179                }
 4180            }
 4181
 4182            if self.auto_replace_emoji_shortcode
 4183                && selection.is_empty()
 4184                && text.as_ref().ends_with(':')
 4185                && let Some(possible_emoji_short_code) =
 4186                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4187                && !possible_emoji_short_code.is_empty()
 4188                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4189            {
 4190                let emoji_shortcode_start = Point::new(
 4191                    selection.start.row,
 4192                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4193                );
 4194
 4195                // Remove shortcode from buffer
 4196                edits.push((
 4197                    emoji_shortcode_start..selection.start,
 4198                    "".to_string().into(),
 4199                ));
 4200                new_selections.push((
 4201                    Selection {
 4202                        id: selection.id,
 4203                        start: snapshot.anchor_after(emoji_shortcode_start),
 4204                        end: snapshot.anchor_before(selection.start),
 4205                        reversed: selection.reversed,
 4206                        goal: selection.goal,
 4207                    },
 4208                    0,
 4209                ));
 4210
 4211                // Insert emoji
 4212                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4213                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4214                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4215
 4216                continue;
 4217            }
 4218
 4219            // If not handling any auto-close operation, then just replace the selected
 4220            // text with the given input and move the selection to the end of the
 4221            // newly inserted text.
 4222            let anchor = snapshot.anchor_after(selection.end);
 4223            if !self.linked_edit_ranges.is_empty() {
 4224                let start_anchor = snapshot.anchor_before(selection.start);
 4225
 4226                let is_word_char = text.chars().next().is_none_or(|char| {
 4227                    let classifier = snapshot
 4228                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4229                        .ignore_punctuation(true);
 4230                    classifier.is_word(char)
 4231                });
 4232
 4233                if is_word_char {
 4234                    if let Some(ranges) = self
 4235                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4236                    {
 4237                        for (buffer, edits) in ranges {
 4238                            linked_edits
 4239                                .entry(buffer.clone())
 4240                                .or_default()
 4241                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4242                        }
 4243                    }
 4244                } else {
 4245                    clear_linked_edit_ranges = true;
 4246                }
 4247            }
 4248
 4249            new_selections.push((selection.map(|_| anchor), 0));
 4250            edits.push((selection.start..selection.end, text.clone()));
 4251        }
 4252
 4253        drop(snapshot);
 4254
 4255        self.transact(window, cx, |this, window, cx| {
 4256            if clear_linked_edit_ranges {
 4257                this.linked_edit_ranges.clear();
 4258            }
 4259            let initial_buffer_versions =
 4260                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4261
 4262            this.buffer.update(cx, |buffer, cx| {
 4263                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4264            });
 4265            for (buffer, edits) in linked_edits {
 4266                buffer.update(cx, |buffer, cx| {
 4267                    let snapshot = buffer.snapshot();
 4268                    let edits = edits
 4269                        .into_iter()
 4270                        .map(|(range, text)| {
 4271                            use text::ToPoint as TP;
 4272                            let end_point = TP::to_point(&range.end, &snapshot);
 4273                            let start_point = TP::to_point(&range.start, &snapshot);
 4274                            (start_point..end_point, text)
 4275                        })
 4276                        .sorted_by_key(|(range, _)| range.start);
 4277                    buffer.edit(edits, None, cx);
 4278                })
 4279            }
 4280            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4281            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4282            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4283            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4284                .zip(new_selection_deltas)
 4285                .map(|(selection, delta)| Selection {
 4286                    id: selection.id,
 4287                    start: selection.start + delta,
 4288                    end: selection.end + delta,
 4289                    reversed: selection.reversed,
 4290                    goal: SelectionGoal::None,
 4291                })
 4292                .collect::<Vec<_>>();
 4293
 4294            let mut i = 0;
 4295            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4296                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4297                let start = map.buffer_snapshot.anchor_before(position);
 4298                let end = map.buffer_snapshot.anchor_after(position);
 4299                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4300                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4301                        Ordering::Less => i += 1,
 4302                        Ordering::Greater => break,
 4303                        Ordering::Equal => {
 4304                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4305                                Ordering::Less => i += 1,
 4306                                Ordering::Equal => break,
 4307                                Ordering::Greater => break,
 4308                            }
 4309                        }
 4310                    }
 4311                }
 4312                this.autoclose_regions.insert(
 4313                    i,
 4314                    AutocloseRegion {
 4315                        selection_id,
 4316                        range: start..end,
 4317                        pair,
 4318                    },
 4319                );
 4320            }
 4321
 4322            let had_active_edit_prediction = this.has_active_edit_prediction();
 4323            this.change_selections(
 4324                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4325                window,
 4326                cx,
 4327                |s| s.select(new_selections),
 4328            );
 4329
 4330            if !bracket_inserted
 4331                && let Some(on_type_format_task) =
 4332                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4333            {
 4334                on_type_format_task.detach_and_log_err(cx);
 4335            }
 4336
 4337            let editor_settings = EditorSettings::get_global(cx);
 4338            if bracket_inserted
 4339                && (editor_settings.auto_signature_help
 4340                    || editor_settings.show_signature_help_after_edits)
 4341            {
 4342                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4343            }
 4344
 4345            let trigger_in_words =
 4346                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4347            if this.hard_wrap.is_some() {
 4348                let latest: Range<Point> = this.selections.newest(cx).range();
 4349                if latest.is_empty()
 4350                    && this
 4351                        .buffer()
 4352                        .read(cx)
 4353                        .snapshot(cx)
 4354                        .line_len(MultiBufferRow(latest.start.row))
 4355                        == latest.start.column
 4356                {
 4357                    this.rewrap_impl(
 4358                        RewrapOptions {
 4359                            override_language_settings: true,
 4360                            preserve_existing_whitespace: true,
 4361                        },
 4362                        cx,
 4363                    )
 4364                }
 4365            }
 4366            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4367            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4368            this.refresh_edit_prediction(true, false, window, cx);
 4369            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4370        });
 4371    }
 4372
 4373    fn find_possible_emoji_shortcode_at_position(
 4374        snapshot: &MultiBufferSnapshot,
 4375        position: Point,
 4376    ) -> Option<String> {
 4377        let mut chars = Vec::new();
 4378        let mut found_colon = false;
 4379        for char in snapshot.reversed_chars_at(position).take(100) {
 4380            // Found a possible emoji shortcode in the middle of the buffer
 4381            if found_colon {
 4382                if char.is_whitespace() {
 4383                    chars.reverse();
 4384                    return Some(chars.iter().collect());
 4385                }
 4386                // If the previous character is not a whitespace, we are in the middle of a word
 4387                // and we only want to complete the shortcode if the word is made up of other emojis
 4388                let mut containing_word = String::new();
 4389                for ch in snapshot
 4390                    .reversed_chars_at(position)
 4391                    .skip(chars.len() + 1)
 4392                    .take(100)
 4393                {
 4394                    if ch.is_whitespace() {
 4395                        break;
 4396                    }
 4397                    containing_word.push(ch);
 4398                }
 4399                let containing_word = containing_word.chars().rev().collect::<String>();
 4400                if util::word_consists_of_emojis(containing_word.as_str()) {
 4401                    chars.reverse();
 4402                    return Some(chars.iter().collect());
 4403                }
 4404            }
 4405
 4406            if char.is_whitespace() || !char.is_ascii() {
 4407                return None;
 4408            }
 4409            if char == ':' {
 4410                found_colon = true;
 4411            } else {
 4412                chars.push(char);
 4413            }
 4414        }
 4415        // Found a possible emoji shortcode at the beginning of the buffer
 4416        chars.reverse();
 4417        Some(chars.iter().collect())
 4418    }
 4419
 4420    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4421        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4422        self.transact(window, cx, |this, window, cx| {
 4423            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4424                let selections = this.selections.all::<usize>(cx);
 4425                let multi_buffer = this.buffer.read(cx);
 4426                let buffer = multi_buffer.snapshot(cx);
 4427                selections
 4428                    .iter()
 4429                    .map(|selection| {
 4430                        let start_point = selection.start.to_point(&buffer);
 4431                        let mut existing_indent =
 4432                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4433                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4434                        let start = selection.start;
 4435                        let end = selection.end;
 4436                        let selection_is_empty = start == end;
 4437                        let language_scope = buffer.language_scope_at(start);
 4438                        let (
 4439                            comment_delimiter,
 4440                            doc_delimiter,
 4441                            insert_extra_newline,
 4442                            indent_on_newline,
 4443                            indent_on_extra_newline,
 4444                        ) = if let Some(language) = &language_scope {
 4445                            let mut insert_extra_newline =
 4446                                insert_extra_newline_brackets(&buffer, start..end, language)
 4447                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4448
 4449                            // Comment extension on newline is allowed only for cursor selections
 4450                            let comment_delimiter = maybe!({
 4451                                if !selection_is_empty {
 4452                                    return None;
 4453                                }
 4454
 4455                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4456                                    return None;
 4457                                }
 4458
 4459                                let delimiters = language.line_comment_prefixes();
 4460                                let max_len_of_delimiter =
 4461                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4462                                let (snapshot, range) =
 4463                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4464
 4465                                let num_of_whitespaces = snapshot
 4466                                    .chars_for_range(range.clone())
 4467                                    .take_while(|c| c.is_whitespace())
 4468                                    .count();
 4469                                let comment_candidate = snapshot
 4470                                    .chars_for_range(range.clone())
 4471                                    .skip(num_of_whitespaces)
 4472                                    .take(max_len_of_delimiter)
 4473                                    .collect::<String>();
 4474                                let (delimiter, trimmed_len) = delimiters
 4475                                    .iter()
 4476                                    .filter_map(|delimiter| {
 4477                                        let prefix = delimiter.trim_end();
 4478                                        if comment_candidate.starts_with(prefix) {
 4479                                            Some((delimiter, prefix.len()))
 4480                                        } else {
 4481                                            None
 4482                                        }
 4483                                    })
 4484                                    .max_by_key(|(_, len)| *len)?;
 4485
 4486                                if let Some(BlockCommentConfig {
 4487                                    start: block_start, ..
 4488                                }) = language.block_comment()
 4489                                {
 4490                                    let block_start_trimmed = block_start.trim_end();
 4491                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4492                                        let line_content = snapshot
 4493                                            .chars_for_range(range)
 4494                                            .skip(num_of_whitespaces)
 4495                                            .take(block_start_trimmed.len())
 4496                                            .collect::<String>();
 4497
 4498                                        if line_content.starts_with(block_start_trimmed) {
 4499                                            return None;
 4500                                        }
 4501                                    }
 4502                                }
 4503
 4504                                let cursor_is_placed_after_comment_marker =
 4505                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4506                                if cursor_is_placed_after_comment_marker {
 4507                                    Some(delimiter.clone())
 4508                                } else {
 4509                                    None
 4510                                }
 4511                            });
 4512
 4513                            let mut indent_on_newline = IndentSize::spaces(0);
 4514                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4515
 4516                            let doc_delimiter = maybe!({
 4517                                if !selection_is_empty {
 4518                                    return None;
 4519                                }
 4520
 4521                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4522                                    return None;
 4523                                }
 4524
 4525                                let BlockCommentConfig {
 4526                                    start: start_tag,
 4527                                    end: end_tag,
 4528                                    prefix: delimiter,
 4529                                    tab_size: len,
 4530                                } = language.documentation_comment()?;
 4531                                let is_within_block_comment = buffer
 4532                                    .language_scope_at(start_point)
 4533                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4534                                if !is_within_block_comment {
 4535                                    return None;
 4536                                }
 4537
 4538                                let (snapshot, range) =
 4539                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4540
 4541                                let num_of_whitespaces = snapshot
 4542                                    .chars_for_range(range.clone())
 4543                                    .take_while(|c| c.is_whitespace())
 4544                                    .count();
 4545
 4546                                // 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.
 4547                                let column = start_point.column;
 4548                                let cursor_is_after_start_tag = {
 4549                                    let start_tag_len = start_tag.len();
 4550                                    let start_tag_line = snapshot
 4551                                        .chars_for_range(range.clone())
 4552                                        .skip(num_of_whitespaces)
 4553                                        .take(start_tag_len)
 4554                                        .collect::<String>();
 4555                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4556                                        num_of_whitespaces + start_tag_len <= column as usize
 4557                                    } else {
 4558                                        false
 4559                                    }
 4560                                };
 4561
 4562                                let cursor_is_after_delimiter = {
 4563                                    let delimiter_trim = delimiter.trim_end();
 4564                                    let delimiter_line = snapshot
 4565                                        .chars_for_range(range.clone())
 4566                                        .skip(num_of_whitespaces)
 4567                                        .take(delimiter_trim.len())
 4568                                        .collect::<String>();
 4569                                    if delimiter_line.starts_with(delimiter_trim) {
 4570                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4571                                    } else {
 4572                                        false
 4573                                    }
 4574                                };
 4575
 4576                                let cursor_is_before_end_tag_if_exists = {
 4577                                    let mut char_position = 0u32;
 4578                                    let mut end_tag_offset = None;
 4579
 4580                                    'outer: for chunk in snapshot.text_for_range(range) {
 4581                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4582                                            let chars_before_match =
 4583                                                chunk[..byte_pos].chars().count() as u32;
 4584                                            end_tag_offset =
 4585                                                Some(char_position + chars_before_match);
 4586                                            break 'outer;
 4587                                        }
 4588                                        char_position += chunk.chars().count() as u32;
 4589                                    }
 4590
 4591                                    if let Some(end_tag_offset) = end_tag_offset {
 4592                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4593                                        if cursor_is_after_start_tag {
 4594                                            if cursor_is_before_end_tag {
 4595                                                insert_extra_newline = true;
 4596                                            }
 4597                                            let cursor_is_at_start_of_end_tag =
 4598                                                column == end_tag_offset;
 4599                                            if cursor_is_at_start_of_end_tag {
 4600                                                indent_on_extra_newline.len = *len;
 4601                                            }
 4602                                        }
 4603                                        cursor_is_before_end_tag
 4604                                    } else {
 4605                                        true
 4606                                    }
 4607                                };
 4608
 4609                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4610                                    && cursor_is_before_end_tag_if_exists
 4611                                {
 4612                                    if cursor_is_after_start_tag {
 4613                                        indent_on_newline.len = *len;
 4614                                    }
 4615                                    Some(delimiter.clone())
 4616                                } else {
 4617                                    None
 4618                                }
 4619                            });
 4620
 4621                            (
 4622                                comment_delimiter,
 4623                                doc_delimiter,
 4624                                insert_extra_newline,
 4625                                indent_on_newline,
 4626                                indent_on_extra_newline,
 4627                            )
 4628                        } else {
 4629                            (
 4630                                None,
 4631                                None,
 4632                                false,
 4633                                IndentSize::default(),
 4634                                IndentSize::default(),
 4635                            )
 4636                        };
 4637
 4638                        let prevent_auto_indent = doc_delimiter.is_some();
 4639                        let delimiter = comment_delimiter.or(doc_delimiter);
 4640
 4641                        let capacity_for_delimiter =
 4642                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4643                        let mut new_text = String::with_capacity(
 4644                            1 + capacity_for_delimiter
 4645                                + existing_indent.len as usize
 4646                                + indent_on_newline.len as usize
 4647                                + indent_on_extra_newline.len as usize,
 4648                        );
 4649                        new_text.push('\n');
 4650                        new_text.extend(existing_indent.chars());
 4651                        new_text.extend(indent_on_newline.chars());
 4652
 4653                        if let Some(delimiter) = &delimiter {
 4654                            new_text.push_str(delimiter);
 4655                        }
 4656
 4657                        if insert_extra_newline {
 4658                            new_text.push('\n');
 4659                            new_text.extend(existing_indent.chars());
 4660                            new_text.extend(indent_on_extra_newline.chars());
 4661                        }
 4662
 4663                        let anchor = buffer.anchor_after(end);
 4664                        let new_selection = selection.map(|_| anchor);
 4665                        (
 4666                            ((start..end, new_text), prevent_auto_indent),
 4667                            (insert_extra_newline, new_selection),
 4668                        )
 4669                    })
 4670                    .unzip()
 4671            };
 4672
 4673            let mut auto_indent_edits = Vec::new();
 4674            let mut edits = Vec::new();
 4675            for (edit, prevent_auto_indent) in edits_with_flags {
 4676                if prevent_auto_indent {
 4677                    edits.push(edit);
 4678                } else {
 4679                    auto_indent_edits.push(edit);
 4680                }
 4681            }
 4682            if !edits.is_empty() {
 4683                this.edit(edits, cx);
 4684            }
 4685            if !auto_indent_edits.is_empty() {
 4686                this.edit_with_autoindent(auto_indent_edits, cx);
 4687            }
 4688
 4689            let buffer = this.buffer.read(cx).snapshot(cx);
 4690            let new_selections = selection_info
 4691                .into_iter()
 4692                .map(|(extra_newline_inserted, new_selection)| {
 4693                    let mut cursor = new_selection.end.to_point(&buffer);
 4694                    if extra_newline_inserted {
 4695                        cursor.row -= 1;
 4696                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4697                    }
 4698                    new_selection.map(|_| cursor)
 4699                })
 4700                .collect();
 4701
 4702            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4703            this.refresh_edit_prediction(true, false, window, cx);
 4704        });
 4705    }
 4706
 4707    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4708        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4709
 4710        let buffer = self.buffer.read(cx);
 4711        let snapshot = buffer.snapshot(cx);
 4712
 4713        let mut edits = Vec::new();
 4714        let mut rows = Vec::new();
 4715
 4716        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4717            let cursor = selection.head();
 4718            let row = cursor.row;
 4719
 4720            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4721
 4722            let newline = "\n".to_string();
 4723            edits.push((start_of_line..start_of_line, newline));
 4724
 4725            rows.push(row + rows_inserted as u32);
 4726        }
 4727
 4728        self.transact(window, cx, |editor, window, cx| {
 4729            editor.edit(edits, cx);
 4730
 4731            editor.change_selections(Default::default(), window, cx, |s| {
 4732                let mut index = 0;
 4733                s.move_cursors_with(|map, _, _| {
 4734                    let row = rows[index];
 4735                    index += 1;
 4736
 4737                    let point = Point::new(row, 0);
 4738                    let boundary = map.next_line_boundary(point).1;
 4739                    let clipped = map.clip_point(boundary, Bias::Left);
 4740
 4741                    (clipped, SelectionGoal::None)
 4742                });
 4743            });
 4744
 4745            let mut indent_edits = Vec::new();
 4746            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4747            for row in rows {
 4748                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4749                for (row, indent) in indents {
 4750                    if indent.len == 0 {
 4751                        continue;
 4752                    }
 4753
 4754                    let text = match indent.kind {
 4755                        IndentKind::Space => " ".repeat(indent.len as usize),
 4756                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4757                    };
 4758                    let point = Point::new(row.0, 0);
 4759                    indent_edits.push((point..point, text));
 4760                }
 4761            }
 4762            editor.edit(indent_edits, cx);
 4763        });
 4764    }
 4765
 4766    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4767        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4768
 4769        let buffer = self.buffer.read(cx);
 4770        let snapshot = buffer.snapshot(cx);
 4771
 4772        let mut edits = Vec::new();
 4773        let mut rows = Vec::new();
 4774        let mut rows_inserted = 0;
 4775
 4776        for selection in self.selections.all_adjusted(cx) {
 4777            let cursor = selection.head();
 4778            let row = cursor.row;
 4779
 4780            let point = Point::new(row + 1, 0);
 4781            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4782
 4783            let newline = "\n".to_string();
 4784            edits.push((start_of_line..start_of_line, newline));
 4785
 4786            rows_inserted += 1;
 4787            rows.push(row + rows_inserted);
 4788        }
 4789
 4790        self.transact(window, cx, |editor, window, cx| {
 4791            editor.edit(edits, cx);
 4792
 4793            editor.change_selections(Default::default(), window, cx, |s| {
 4794                let mut index = 0;
 4795                s.move_cursors_with(|map, _, _| {
 4796                    let row = rows[index];
 4797                    index += 1;
 4798
 4799                    let point = Point::new(row, 0);
 4800                    let boundary = map.next_line_boundary(point).1;
 4801                    let clipped = map.clip_point(boundary, Bias::Left);
 4802
 4803                    (clipped, SelectionGoal::None)
 4804                });
 4805            });
 4806
 4807            let mut indent_edits = Vec::new();
 4808            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4809            for row in rows {
 4810                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4811                for (row, indent) in indents {
 4812                    if indent.len == 0 {
 4813                        continue;
 4814                    }
 4815
 4816                    let text = match indent.kind {
 4817                        IndentKind::Space => " ".repeat(indent.len as usize),
 4818                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4819                    };
 4820                    let point = Point::new(row.0, 0);
 4821                    indent_edits.push((point..point, text));
 4822                }
 4823            }
 4824            editor.edit(indent_edits, cx);
 4825        });
 4826    }
 4827
 4828    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4829        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4830            original_indent_columns: Vec::new(),
 4831        });
 4832        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4833    }
 4834
 4835    fn insert_with_autoindent_mode(
 4836        &mut self,
 4837        text: &str,
 4838        autoindent_mode: Option<AutoindentMode>,
 4839        window: &mut Window,
 4840        cx: &mut Context<Self>,
 4841    ) {
 4842        if self.read_only(cx) {
 4843            return;
 4844        }
 4845
 4846        let text: Arc<str> = text.into();
 4847        self.transact(window, cx, |this, window, cx| {
 4848            let old_selections = this.selections.all_adjusted(cx);
 4849            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4850                let anchors = {
 4851                    let snapshot = buffer.read(cx);
 4852                    old_selections
 4853                        .iter()
 4854                        .map(|s| {
 4855                            let anchor = snapshot.anchor_after(s.head());
 4856                            s.map(|_| anchor)
 4857                        })
 4858                        .collect::<Vec<_>>()
 4859                };
 4860                buffer.edit(
 4861                    old_selections
 4862                        .iter()
 4863                        .map(|s| (s.start..s.end, text.clone())),
 4864                    autoindent_mode,
 4865                    cx,
 4866                );
 4867                anchors
 4868            });
 4869
 4870            this.change_selections(Default::default(), window, cx, |s| {
 4871                s.select_anchors(selection_anchors);
 4872            });
 4873
 4874            cx.notify();
 4875        });
 4876    }
 4877
 4878    fn trigger_completion_on_input(
 4879        &mut self,
 4880        text: &str,
 4881        trigger_in_words: bool,
 4882        window: &mut Window,
 4883        cx: &mut Context<Self>,
 4884    ) {
 4885        let completions_source = self
 4886            .context_menu
 4887            .borrow()
 4888            .as_ref()
 4889            .and_then(|menu| match menu {
 4890                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4891                CodeContextMenu::CodeActions(_) => None,
 4892            });
 4893
 4894        match completions_source {
 4895            Some(CompletionsMenuSource::Words) => {
 4896                self.show_word_completions(&ShowWordCompletions, window, cx)
 4897            }
 4898            Some(CompletionsMenuSource::Normal)
 4899            | Some(CompletionsMenuSource::SnippetChoices)
 4900            | None
 4901                if self.is_completion_trigger(
 4902                    text,
 4903                    trigger_in_words,
 4904                    completions_source.is_some(),
 4905                    cx,
 4906                ) =>
 4907            {
 4908                self.show_completions(
 4909                    &ShowCompletions {
 4910                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4911                    },
 4912                    window,
 4913                    cx,
 4914                )
 4915            }
 4916            _ => {
 4917                self.hide_context_menu(window, cx);
 4918            }
 4919        }
 4920    }
 4921
 4922    fn is_completion_trigger(
 4923        &self,
 4924        text: &str,
 4925        trigger_in_words: bool,
 4926        menu_is_open: bool,
 4927        cx: &mut Context<Self>,
 4928    ) -> bool {
 4929        let position = self.selections.newest_anchor().head();
 4930        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4931            return false;
 4932        };
 4933
 4934        if let Some(completion_provider) = &self.completion_provider {
 4935            completion_provider.is_completion_trigger(
 4936                &buffer,
 4937                position.text_anchor,
 4938                text,
 4939                trigger_in_words,
 4940                menu_is_open,
 4941                cx,
 4942            )
 4943        } else {
 4944            false
 4945        }
 4946    }
 4947
 4948    /// If any empty selections is touching the start of its innermost containing autoclose
 4949    /// region, expand it to select the brackets.
 4950    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4951        let selections = self.selections.all::<usize>(cx);
 4952        let buffer = self.buffer.read(cx).read(cx);
 4953        let new_selections = self
 4954            .selections_with_autoclose_regions(selections, &buffer)
 4955            .map(|(mut selection, region)| {
 4956                if !selection.is_empty() {
 4957                    return selection;
 4958                }
 4959
 4960                if let Some(region) = region {
 4961                    let mut range = region.range.to_offset(&buffer);
 4962                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4963                        range.start -= region.pair.start.len();
 4964                        if buffer.contains_str_at(range.start, &region.pair.start)
 4965                            && buffer.contains_str_at(range.end, &region.pair.end)
 4966                        {
 4967                            range.end += region.pair.end.len();
 4968                            selection.start = range.start;
 4969                            selection.end = range.end;
 4970
 4971                            return selection;
 4972                        }
 4973                    }
 4974                }
 4975
 4976                let always_treat_brackets_as_autoclosed = buffer
 4977                    .language_settings_at(selection.start, cx)
 4978                    .always_treat_brackets_as_autoclosed;
 4979
 4980                if !always_treat_brackets_as_autoclosed {
 4981                    return selection;
 4982                }
 4983
 4984                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4985                    for (pair, enabled) in scope.brackets() {
 4986                        if !enabled || !pair.close {
 4987                            continue;
 4988                        }
 4989
 4990                        if buffer.contains_str_at(selection.start, &pair.end) {
 4991                            let pair_start_len = pair.start.len();
 4992                            if buffer.contains_str_at(
 4993                                selection.start.saturating_sub(pair_start_len),
 4994                                &pair.start,
 4995                            ) {
 4996                                selection.start -= pair_start_len;
 4997                                selection.end += pair.end.len();
 4998
 4999                                return selection;
 5000                            }
 5001                        }
 5002                    }
 5003                }
 5004
 5005                selection
 5006            })
 5007            .collect();
 5008
 5009        drop(buffer);
 5010        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5011            selections.select(new_selections)
 5012        });
 5013    }
 5014
 5015    /// Iterate the given selections, and for each one, find the smallest surrounding
 5016    /// autoclose region. This uses the ordering of the selections and the autoclose
 5017    /// regions to avoid repeated comparisons.
 5018    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5019        &'a self,
 5020        selections: impl IntoIterator<Item = Selection<D>>,
 5021        buffer: &'a MultiBufferSnapshot,
 5022    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5023        let mut i = 0;
 5024        let mut regions = self.autoclose_regions.as_slice();
 5025        selections.into_iter().map(move |selection| {
 5026            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5027
 5028            let mut enclosing = None;
 5029            while let Some(pair_state) = regions.get(i) {
 5030                if pair_state.range.end.to_offset(buffer) < range.start {
 5031                    regions = &regions[i + 1..];
 5032                    i = 0;
 5033                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5034                    break;
 5035                } else {
 5036                    if pair_state.selection_id == selection.id {
 5037                        enclosing = Some(pair_state);
 5038                    }
 5039                    i += 1;
 5040                }
 5041            }
 5042
 5043            (selection, enclosing)
 5044        })
 5045    }
 5046
 5047    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5048    fn invalidate_autoclose_regions(
 5049        &mut self,
 5050        mut selections: &[Selection<Anchor>],
 5051        buffer: &MultiBufferSnapshot,
 5052    ) {
 5053        self.autoclose_regions.retain(|state| {
 5054            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5055                return false;
 5056            }
 5057
 5058            let mut i = 0;
 5059            while let Some(selection) = selections.get(i) {
 5060                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5061                    selections = &selections[1..];
 5062                    continue;
 5063                }
 5064                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5065                    break;
 5066                }
 5067                if selection.id == state.selection_id {
 5068                    return true;
 5069                } else {
 5070                    i += 1;
 5071                }
 5072            }
 5073            false
 5074        });
 5075    }
 5076
 5077    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5078        let offset = position.to_offset(buffer);
 5079        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5080        if offset > word_range.start && kind == Some(CharKind::Word) {
 5081            Some(
 5082                buffer
 5083                    .text_for_range(word_range.start..offset)
 5084                    .collect::<String>(),
 5085            )
 5086        } else {
 5087            None
 5088        }
 5089    }
 5090
 5091    pub fn toggle_inline_values(
 5092        &mut self,
 5093        _: &ToggleInlineValues,
 5094        _: &mut Window,
 5095        cx: &mut Context<Self>,
 5096    ) {
 5097        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5098
 5099        self.refresh_inline_values(cx);
 5100    }
 5101
 5102    pub fn toggle_inlay_hints(
 5103        &mut self,
 5104        _: &ToggleInlayHints,
 5105        _: &mut Window,
 5106        cx: &mut Context<Self>,
 5107    ) {
 5108        self.refresh_inlay_hints(
 5109            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5110            cx,
 5111        );
 5112    }
 5113
 5114    pub fn inlay_hints_enabled(&self) -> bool {
 5115        self.inlay_hint_cache.enabled
 5116    }
 5117
 5118    pub fn inline_values_enabled(&self) -> bool {
 5119        self.inline_value_cache.enabled
 5120    }
 5121
 5122    #[cfg(any(test, feature = "test-support"))]
 5123    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5124        self.display_map
 5125            .read(cx)
 5126            .current_inlays()
 5127            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5128            .cloned()
 5129            .collect()
 5130    }
 5131
 5132    #[cfg(any(test, feature = "test-support"))]
 5133    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5134        self.display_map
 5135            .read(cx)
 5136            .current_inlays()
 5137            .cloned()
 5138            .collect()
 5139    }
 5140
 5141    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5142        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5143            return;
 5144        }
 5145
 5146        let reason_description = reason.description();
 5147        let ignore_debounce = matches!(
 5148            reason,
 5149            InlayHintRefreshReason::SettingsChange(_)
 5150                | InlayHintRefreshReason::Toggle(_)
 5151                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5152                | InlayHintRefreshReason::ModifiersChanged(_)
 5153        );
 5154        let (invalidate_cache, required_languages) = match reason {
 5155            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5156                match self.inlay_hint_cache.modifiers_override(enabled) {
 5157                    Some(enabled) => {
 5158                        if enabled {
 5159                            (InvalidationStrategy::RefreshRequested, None)
 5160                        } else {
 5161                            self.splice_inlays(
 5162                                &self
 5163                                    .visible_inlay_hints(cx)
 5164                                    .iter()
 5165                                    .map(|inlay| inlay.id)
 5166                                    .collect::<Vec<InlayId>>(),
 5167                                Vec::new(),
 5168                                cx,
 5169                            );
 5170                            return;
 5171                        }
 5172                    }
 5173                    None => return,
 5174                }
 5175            }
 5176            InlayHintRefreshReason::Toggle(enabled) => {
 5177                if self.inlay_hint_cache.toggle(enabled) {
 5178                    if enabled {
 5179                        (InvalidationStrategy::RefreshRequested, None)
 5180                    } else {
 5181                        self.splice_inlays(
 5182                            &self
 5183                                .visible_inlay_hints(cx)
 5184                                .iter()
 5185                                .map(|inlay| inlay.id)
 5186                                .collect::<Vec<InlayId>>(),
 5187                            Vec::new(),
 5188                            cx,
 5189                        );
 5190                        return;
 5191                    }
 5192                } else {
 5193                    return;
 5194                }
 5195            }
 5196            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5197                match self.inlay_hint_cache.update_settings(
 5198                    &self.buffer,
 5199                    new_settings,
 5200                    self.visible_inlay_hints(cx),
 5201                    cx,
 5202                ) {
 5203                    ControlFlow::Break(Some(InlaySplice {
 5204                        to_remove,
 5205                        to_insert,
 5206                    })) => {
 5207                        self.splice_inlays(&to_remove, to_insert, cx);
 5208                        return;
 5209                    }
 5210                    ControlFlow::Break(None) => return,
 5211                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5212                }
 5213            }
 5214            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5215                if let Some(InlaySplice {
 5216                    to_remove,
 5217                    to_insert,
 5218                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5219                {
 5220                    self.splice_inlays(&to_remove, to_insert, cx);
 5221                }
 5222                self.display_map.update(cx, |display_map, _| {
 5223                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5224                });
 5225                return;
 5226            }
 5227            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5228            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5229                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5230            }
 5231            InlayHintRefreshReason::RefreshRequested => {
 5232                (InvalidationStrategy::RefreshRequested, None)
 5233            }
 5234        };
 5235
 5236        if let Some(InlaySplice {
 5237            to_remove,
 5238            to_insert,
 5239        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5240            reason_description,
 5241            self.visible_excerpts(required_languages.as_ref(), cx),
 5242            invalidate_cache,
 5243            ignore_debounce,
 5244            cx,
 5245        ) {
 5246            self.splice_inlays(&to_remove, to_insert, cx);
 5247        }
 5248    }
 5249
 5250    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5251        self.display_map
 5252            .read(cx)
 5253            .current_inlays()
 5254            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5255            .cloned()
 5256            .collect()
 5257    }
 5258
 5259    pub fn visible_excerpts(
 5260        &self,
 5261        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5262        cx: &mut Context<Editor>,
 5263    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5264        let Some(project) = self.project() else {
 5265            return HashMap::default();
 5266        };
 5267        let project = project.read(cx);
 5268        let multi_buffer = self.buffer().read(cx);
 5269        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5270        let multi_buffer_visible_start = self
 5271            .scroll_manager
 5272            .anchor()
 5273            .anchor
 5274            .to_point(&multi_buffer_snapshot);
 5275        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5276            multi_buffer_visible_start
 5277                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5278            Bias::Left,
 5279        );
 5280        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5281        multi_buffer_snapshot
 5282            .range_to_buffer_ranges(multi_buffer_visible_range)
 5283            .into_iter()
 5284            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5285            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5286                let buffer_file = project::File::from_dyn(buffer.file())?;
 5287                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5288                let worktree_entry = buffer_worktree
 5289                    .read(cx)
 5290                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5291                if worktree_entry.is_ignored {
 5292                    return None;
 5293                }
 5294
 5295                let language = buffer.language()?;
 5296                if let Some(restrict_to_languages) = restrict_to_languages
 5297                    && !restrict_to_languages.contains(language)
 5298                {
 5299                    return None;
 5300                }
 5301                Some((
 5302                    excerpt_id,
 5303                    (
 5304                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5305                        buffer.version().clone(),
 5306                        excerpt_visible_range,
 5307                    ),
 5308                ))
 5309            })
 5310            .collect()
 5311    }
 5312
 5313    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5314        TextLayoutDetails {
 5315            text_system: window.text_system().clone(),
 5316            editor_style: self.style.clone().unwrap(),
 5317            rem_size: window.rem_size(),
 5318            scroll_anchor: self.scroll_manager.anchor(),
 5319            visible_rows: self.visible_line_count(),
 5320            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5321        }
 5322    }
 5323
 5324    pub fn splice_inlays(
 5325        &self,
 5326        to_remove: &[InlayId],
 5327        to_insert: Vec<Inlay>,
 5328        cx: &mut Context<Self>,
 5329    ) {
 5330        self.display_map.update(cx, |display_map, cx| {
 5331            display_map.splice_inlays(to_remove, to_insert, cx)
 5332        });
 5333        cx.notify();
 5334    }
 5335
 5336    fn trigger_on_type_formatting(
 5337        &self,
 5338        input: String,
 5339        window: &mut Window,
 5340        cx: &mut Context<Self>,
 5341    ) -> Option<Task<Result<()>>> {
 5342        if input.len() != 1 {
 5343            return None;
 5344        }
 5345
 5346        let project = self.project()?;
 5347        let position = self.selections.newest_anchor().head();
 5348        let (buffer, buffer_position) = self
 5349            .buffer
 5350            .read(cx)
 5351            .text_anchor_for_position(position, cx)?;
 5352
 5353        let settings = language_settings::language_settings(
 5354            buffer
 5355                .read(cx)
 5356                .language_at(buffer_position)
 5357                .map(|l| l.name()),
 5358            buffer.read(cx).file(),
 5359            cx,
 5360        );
 5361        if !settings.use_on_type_format {
 5362            return None;
 5363        }
 5364
 5365        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5366        // hence we do LSP request & edit on host side only — add formats to host's history.
 5367        let push_to_lsp_host_history = true;
 5368        // If this is not the host, append its history with new edits.
 5369        let push_to_client_history = project.read(cx).is_via_collab();
 5370
 5371        let on_type_formatting = project.update(cx, |project, cx| {
 5372            project.on_type_format(
 5373                buffer.clone(),
 5374                buffer_position,
 5375                input,
 5376                push_to_lsp_host_history,
 5377                cx,
 5378            )
 5379        });
 5380        Some(cx.spawn_in(window, async move |editor, cx| {
 5381            if let Some(transaction) = on_type_formatting.await? {
 5382                if push_to_client_history {
 5383                    buffer
 5384                        .update(cx, |buffer, _| {
 5385                            buffer.push_transaction(transaction, Instant::now());
 5386                            buffer.finalize_last_transaction();
 5387                        })
 5388                        .ok();
 5389                }
 5390                editor.update(cx, |editor, cx| {
 5391                    editor.refresh_document_highlights(cx);
 5392                })?;
 5393            }
 5394            Ok(())
 5395        }))
 5396    }
 5397
 5398    pub fn show_word_completions(
 5399        &mut self,
 5400        _: &ShowWordCompletions,
 5401        window: &mut Window,
 5402        cx: &mut Context<Self>,
 5403    ) {
 5404        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5405    }
 5406
 5407    pub fn show_completions(
 5408        &mut self,
 5409        options: &ShowCompletions,
 5410        window: &mut Window,
 5411        cx: &mut Context<Self>,
 5412    ) {
 5413        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5414    }
 5415
 5416    fn open_or_update_completions_menu(
 5417        &mut self,
 5418        requested_source: Option<CompletionsMenuSource>,
 5419        trigger: Option<&str>,
 5420        window: &mut Window,
 5421        cx: &mut Context<Self>,
 5422    ) {
 5423        if self.pending_rename.is_some() {
 5424            return;
 5425        }
 5426
 5427        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5428
 5429        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5430        // inserted and selected. To handle that case, the start of the selection is used so that
 5431        // the menu starts with all choices.
 5432        let position = self
 5433            .selections
 5434            .newest_anchor()
 5435            .start
 5436            .bias_right(&multibuffer_snapshot);
 5437        if position.diff_base_anchor.is_some() {
 5438            return;
 5439        }
 5440        let (buffer, buffer_position) =
 5441            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5442                output
 5443            } else {
 5444                return;
 5445            };
 5446        let buffer_snapshot = buffer.read(cx).snapshot();
 5447
 5448        let query: Option<Arc<String>> =
 5449            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5450
 5451        drop(multibuffer_snapshot);
 5452
 5453        let provider = match requested_source {
 5454            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5455            Some(CompletionsMenuSource::Words) => None,
 5456            Some(CompletionsMenuSource::SnippetChoices) => {
 5457                log::error!("bug: SnippetChoices requested_source is not handled");
 5458                None
 5459            }
 5460        };
 5461
 5462        let sort_completions = provider
 5463            .as_ref()
 5464            .is_some_and(|provider| provider.sort_completions());
 5465
 5466        let filter_completions = provider
 5467            .as_ref()
 5468            .is_none_or(|provider| provider.filter_completions());
 5469
 5470        let trigger_kind = match trigger {
 5471            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5472                CompletionTriggerKind::TRIGGER_CHARACTER
 5473            }
 5474            _ => CompletionTriggerKind::INVOKED,
 5475        };
 5476        let completion_context = CompletionContext {
 5477            trigger_character: trigger.and_then(|trigger| {
 5478                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5479                    Some(String::from(trigger))
 5480                } else {
 5481                    None
 5482                }
 5483            }),
 5484            trigger_kind,
 5485        };
 5486
 5487        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5488        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5489        // involve trigger chars, so this is skipped in that case.
 5490        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5491        {
 5492            let menu_is_open = matches!(
 5493                self.context_menu.borrow().as_ref(),
 5494                Some(CodeContextMenu::Completions(_))
 5495            );
 5496            if menu_is_open {
 5497                self.hide_context_menu(window, cx);
 5498            }
 5499        }
 5500
 5501        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5502            if filter_completions {
 5503                menu.filter(query.clone(), provider.clone(), window, cx);
 5504            }
 5505            // When `is_incomplete` is false, no need to re-query completions when the current query
 5506            // is a suffix of the initial query.
 5507            if !menu.is_incomplete {
 5508                // If the new query is a suffix of the old query (typing more characters) and
 5509                // the previous result was complete, the existing completions can be filtered.
 5510                //
 5511                // Note that this is always true for snippet completions.
 5512                let query_matches = match (&menu.initial_query, &query) {
 5513                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5514                    (None, _) => true,
 5515                    _ => false,
 5516                };
 5517                if query_matches {
 5518                    let position_matches = if menu.initial_position == position {
 5519                        true
 5520                    } else {
 5521                        let snapshot = self.buffer.read(cx).read(cx);
 5522                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5523                    };
 5524                    if position_matches {
 5525                        return;
 5526                    }
 5527                }
 5528            }
 5529        };
 5530
 5531        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5532            buffer_snapshot.surrounding_word(buffer_position, false)
 5533        {
 5534            let word_to_exclude = buffer_snapshot
 5535                .text_for_range(word_range.clone())
 5536                .collect::<String>();
 5537            (
 5538                buffer_snapshot.anchor_before(word_range.start)
 5539                    ..buffer_snapshot.anchor_after(buffer_position),
 5540                Some(word_to_exclude),
 5541            )
 5542        } else {
 5543            (buffer_position..buffer_position, None)
 5544        };
 5545
 5546        let language = buffer_snapshot
 5547            .language_at(buffer_position)
 5548            .map(|language| language.name());
 5549
 5550        let completion_settings =
 5551            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5552
 5553        let show_completion_documentation = buffer_snapshot
 5554            .settings_at(buffer_position, cx)
 5555            .show_completion_documentation;
 5556
 5557        // The document can be large, so stay in reasonable bounds when searching for words,
 5558        // otherwise completion pop-up might be slow to appear.
 5559        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5560        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5561        let min_word_search = buffer_snapshot.clip_point(
 5562            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5563            Bias::Left,
 5564        );
 5565        let max_word_search = buffer_snapshot.clip_point(
 5566            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5567            Bias::Right,
 5568        );
 5569        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5570            ..buffer_snapshot.point_to_offset(max_word_search);
 5571
 5572        let skip_digits = query
 5573            .as_ref()
 5574            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5575
 5576        let omit_word_completions = match &query {
 5577            Some(query) => query.chars().count() < completion_settings.words_min_length,
 5578            None => completion_settings.words_min_length != 0,
 5579        };
 5580
 5581        let (mut words, provider_responses) = match &provider {
 5582            Some(provider) => {
 5583                let provider_responses = provider.completions(
 5584                    position.excerpt_id,
 5585                    &buffer,
 5586                    buffer_position,
 5587                    completion_context,
 5588                    window,
 5589                    cx,
 5590                );
 5591
 5592                let words = match (omit_word_completions, completion_settings.words) {
 5593                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5594                        Task::ready(BTreeMap::default())
 5595                    }
 5596                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5597                        .background_spawn(async move {
 5598                            buffer_snapshot.words_in_range(WordsQuery {
 5599                                fuzzy_contents: None,
 5600                                range: word_search_range,
 5601                                skip_digits,
 5602                            })
 5603                        }),
 5604                };
 5605
 5606                (words, provider_responses)
 5607            }
 5608            None => {
 5609                let words = if omit_word_completions {
 5610                    Task::ready(BTreeMap::default())
 5611                } else {
 5612                    cx.background_spawn(async move {
 5613                        buffer_snapshot.words_in_range(WordsQuery {
 5614                            fuzzy_contents: None,
 5615                            range: word_search_range,
 5616                            skip_digits,
 5617                        })
 5618                    })
 5619                };
 5620                (words, Task::ready(Ok(Vec::new())))
 5621            }
 5622        };
 5623
 5624        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5625
 5626        let id = post_inc(&mut self.next_completion_id);
 5627        let task = cx.spawn_in(window, async move |editor, cx| {
 5628            let Ok(()) = editor.update(cx, |this, _| {
 5629                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5630            }) else {
 5631                return;
 5632            };
 5633
 5634            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5635            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5636            let mut completions = Vec::new();
 5637            let mut is_incomplete = false;
 5638            if let Some(provider_responses) = provider_responses.await.log_err()
 5639                && !provider_responses.is_empty()
 5640            {
 5641                for response in provider_responses {
 5642                    completions.extend(response.completions);
 5643                    is_incomplete = is_incomplete || response.is_incomplete;
 5644                }
 5645                if completion_settings.words == WordsCompletionMode::Fallback {
 5646                    words = Task::ready(BTreeMap::default());
 5647                }
 5648            }
 5649
 5650            let mut words = words.await;
 5651            if let Some(word_to_exclude) = &word_to_exclude {
 5652                words.remove(word_to_exclude);
 5653            }
 5654            for lsp_completion in &completions {
 5655                words.remove(&lsp_completion.new_text);
 5656            }
 5657            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5658                replace_range: word_replace_range.clone(),
 5659                new_text: word.clone(),
 5660                label: CodeLabel::plain(word, None),
 5661                icon_path: None,
 5662                documentation: None,
 5663                source: CompletionSource::BufferWord {
 5664                    word_range,
 5665                    resolved: false,
 5666                },
 5667                insert_text_mode: Some(InsertTextMode::AS_IS),
 5668                confirm: None,
 5669            }));
 5670
 5671            let menu = if completions.is_empty() {
 5672                None
 5673            } else {
 5674                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5675                    let languages = editor
 5676                        .workspace
 5677                        .as_ref()
 5678                        .and_then(|(workspace, _)| workspace.upgrade())
 5679                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5680                    let menu = CompletionsMenu::new(
 5681                        id,
 5682                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5683                        sort_completions,
 5684                        show_completion_documentation,
 5685                        position,
 5686                        query.clone(),
 5687                        is_incomplete,
 5688                        buffer.clone(),
 5689                        completions.into(),
 5690                        snippet_sort_order,
 5691                        languages,
 5692                        language,
 5693                        cx,
 5694                    );
 5695
 5696                    let query = if filter_completions { query } else { None };
 5697                    let matches_task = if let Some(query) = query {
 5698                        menu.do_async_filtering(query, cx)
 5699                    } else {
 5700                        Task::ready(menu.unfiltered_matches())
 5701                    };
 5702                    (menu, matches_task)
 5703                }) else {
 5704                    return;
 5705                };
 5706
 5707                let matches = matches_task.await;
 5708
 5709                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5710                    // Newer menu already set, so exit.
 5711                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5712                        editor.context_menu.borrow().as_ref()
 5713                        && prev_menu.id > id
 5714                    {
 5715                        return;
 5716                    };
 5717
 5718                    // Only valid to take prev_menu because it the new menu is immediately set
 5719                    // below, or the menu is hidden.
 5720                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5721                        editor.context_menu.borrow_mut().take()
 5722                    {
 5723                        let position_matches =
 5724                            if prev_menu.initial_position == menu.initial_position {
 5725                                true
 5726                            } else {
 5727                                let snapshot = editor.buffer.read(cx).read(cx);
 5728                                prev_menu.initial_position.to_offset(&snapshot)
 5729                                    == menu.initial_position.to_offset(&snapshot)
 5730                            };
 5731                        if position_matches {
 5732                            // Preserve markdown cache before `set_filter_results` because it will
 5733                            // try to populate the documentation cache.
 5734                            menu.preserve_markdown_cache(prev_menu);
 5735                        }
 5736                    };
 5737
 5738                    menu.set_filter_results(matches, provider, window, cx);
 5739                }) else {
 5740                    return;
 5741                };
 5742
 5743                menu.visible().then_some(menu)
 5744            };
 5745
 5746            editor
 5747                .update_in(cx, |editor, window, cx| {
 5748                    if editor.focus_handle.is_focused(window)
 5749                        && let Some(menu) = menu
 5750                    {
 5751                        *editor.context_menu.borrow_mut() =
 5752                            Some(CodeContextMenu::Completions(menu));
 5753
 5754                        crate::hover_popover::hide_hover(editor, cx);
 5755                        if editor.show_edit_predictions_in_menu() {
 5756                            editor.update_visible_edit_prediction(window, cx);
 5757                        } else {
 5758                            editor.discard_edit_prediction(false, cx);
 5759                        }
 5760
 5761                        cx.notify();
 5762                        return;
 5763                    }
 5764
 5765                    if editor.completion_tasks.len() <= 1 {
 5766                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5767                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5768                        // If it was already hidden and we don't show edit predictions in the menu,
 5769                        // we should also show the edit prediction when available.
 5770                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5771                            editor.update_visible_edit_prediction(window, cx);
 5772                        }
 5773                    }
 5774                })
 5775                .ok();
 5776        });
 5777
 5778        self.completion_tasks.push((id, task));
 5779    }
 5780
 5781    #[cfg(feature = "test-support")]
 5782    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5783        let menu = self.context_menu.borrow();
 5784        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5785            let completions = menu.completions.borrow();
 5786            Some(completions.to_vec())
 5787        } else {
 5788            None
 5789        }
 5790    }
 5791
 5792    pub fn with_completions_menu_matching_id<R>(
 5793        &self,
 5794        id: CompletionId,
 5795        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5796    ) -> R {
 5797        let mut context_menu = self.context_menu.borrow_mut();
 5798        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5799            return f(None);
 5800        };
 5801        if completions_menu.id != id {
 5802            return f(None);
 5803        }
 5804        f(Some(completions_menu))
 5805    }
 5806
 5807    pub fn confirm_completion(
 5808        &mut self,
 5809        action: &ConfirmCompletion,
 5810        window: &mut Window,
 5811        cx: &mut Context<Self>,
 5812    ) -> Option<Task<Result<()>>> {
 5813        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5814        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5815    }
 5816
 5817    pub fn confirm_completion_insert(
 5818        &mut self,
 5819        _: &ConfirmCompletionInsert,
 5820        window: &mut Window,
 5821        cx: &mut Context<Self>,
 5822    ) -> Option<Task<Result<()>>> {
 5823        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5824        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5825    }
 5826
 5827    pub fn confirm_completion_replace(
 5828        &mut self,
 5829        _: &ConfirmCompletionReplace,
 5830        window: &mut Window,
 5831        cx: &mut Context<Self>,
 5832    ) -> Option<Task<Result<()>>> {
 5833        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5834        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5835    }
 5836
 5837    pub fn compose_completion(
 5838        &mut self,
 5839        action: &ComposeCompletion,
 5840        window: &mut Window,
 5841        cx: &mut Context<Self>,
 5842    ) -> Option<Task<Result<()>>> {
 5843        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5844        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5845    }
 5846
 5847    fn do_completion(
 5848        &mut self,
 5849        item_ix: Option<usize>,
 5850        intent: CompletionIntent,
 5851        window: &mut Window,
 5852        cx: &mut Context<Editor>,
 5853    ) -> Option<Task<Result<()>>> {
 5854        use language::ToOffset as _;
 5855
 5856        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5857        else {
 5858            return None;
 5859        };
 5860
 5861        let candidate_id = {
 5862            let entries = completions_menu.entries.borrow();
 5863            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5864            if self.show_edit_predictions_in_menu() {
 5865                self.discard_edit_prediction(true, cx);
 5866            }
 5867            mat.candidate_id
 5868        };
 5869
 5870        let completion = completions_menu
 5871            .completions
 5872            .borrow()
 5873            .get(candidate_id)?
 5874            .clone();
 5875        cx.stop_propagation();
 5876
 5877        let buffer_handle = completions_menu.buffer.clone();
 5878
 5879        let CompletionEdit {
 5880            new_text,
 5881            snippet,
 5882            replace_range,
 5883        } = process_completion_for_edit(
 5884            &completion,
 5885            intent,
 5886            &buffer_handle,
 5887            &completions_menu.initial_position.text_anchor,
 5888            cx,
 5889        );
 5890
 5891        let buffer = buffer_handle.read(cx);
 5892        let snapshot = self.buffer.read(cx).snapshot(cx);
 5893        let newest_anchor = self.selections.newest_anchor();
 5894        let replace_range_multibuffer = {
 5895            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5896            let multibuffer_anchor = snapshot
 5897                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5898                .unwrap()
 5899                ..snapshot
 5900                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5901                    .unwrap();
 5902            multibuffer_anchor.start.to_offset(&snapshot)
 5903                ..multibuffer_anchor.end.to_offset(&snapshot)
 5904        };
 5905        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5906            return None;
 5907        }
 5908
 5909        let old_text = buffer
 5910            .text_for_range(replace_range.clone())
 5911            .collect::<String>();
 5912        let lookbehind = newest_anchor
 5913            .start
 5914            .text_anchor
 5915            .to_offset(buffer)
 5916            .saturating_sub(replace_range.start);
 5917        let lookahead = replace_range
 5918            .end
 5919            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5920        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5921        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5922
 5923        let selections = self.selections.all::<usize>(cx);
 5924        let mut ranges = Vec::new();
 5925        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5926
 5927        for selection in &selections {
 5928            let range = if selection.id == newest_anchor.id {
 5929                replace_range_multibuffer.clone()
 5930            } else {
 5931                let mut range = selection.range();
 5932
 5933                // if prefix is present, don't duplicate it
 5934                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5935                    range.start = range.start.saturating_sub(lookbehind);
 5936
 5937                    // if suffix is also present, mimic the newest cursor and replace it
 5938                    if selection.id != newest_anchor.id
 5939                        && snapshot.contains_str_at(range.end, suffix)
 5940                    {
 5941                        range.end += lookahead;
 5942                    }
 5943                }
 5944                range
 5945            };
 5946
 5947            ranges.push(range.clone());
 5948
 5949            if !self.linked_edit_ranges.is_empty() {
 5950                let start_anchor = snapshot.anchor_before(range.start);
 5951                let end_anchor = snapshot.anchor_after(range.end);
 5952                if let Some(ranges) = self
 5953                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5954                {
 5955                    for (buffer, edits) in ranges {
 5956                        linked_edits
 5957                            .entry(buffer.clone())
 5958                            .or_default()
 5959                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5960                    }
 5961                }
 5962            }
 5963        }
 5964
 5965        let common_prefix_len = old_text
 5966            .chars()
 5967            .zip(new_text.chars())
 5968            .take_while(|(a, b)| a == b)
 5969            .map(|(a, _)| a.len_utf8())
 5970            .sum::<usize>();
 5971
 5972        cx.emit(EditorEvent::InputHandled {
 5973            utf16_range_to_replace: None,
 5974            text: new_text[common_prefix_len..].into(),
 5975        });
 5976
 5977        self.transact(window, cx, |editor, window, cx| {
 5978            if let Some(mut snippet) = snippet {
 5979                snippet.text = new_text.to_string();
 5980                editor
 5981                    .insert_snippet(&ranges, snippet, window, cx)
 5982                    .log_err();
 5983            } else {
 5984                editor.buffer.update(cx, |multi_buffer, cx| {
 5985                    let auto_indent = match completion.insert_text_mode {
 5986                        Some(InsertTextMode::AS_IS) => None,
 5987                        _ => editor.autoindent_mode.clone(),
 5988                    };
 5989                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5990                    multi_buffer.edit(edits, auto_indent, cx);
 5991                });
 5992            }
 5993            for (buffer, edits) in linked_edits {
 5994                buffer.update(cx, |buffer, cx| {
 5995                    let snapshot = buffer.snapshot();
 5996                    let edits = edits
 5997                        .into_iter()
 5998                        .map(|(range, text)| {
 5999                            use text::ToPoint as TP;
 6000                            let end_point = TP::to_point(&range.end, &snapshot);
 6001                            let start_point = TP::to_point(&range.start, &snapshot);
 6002                            (start_point..end_point, text)
 6003                        })
 6004                        .sorted_by_key(|(range, _)| range.start);
 6005                    buffer.edit(edits, None, cx);
 6006                })
 6007            }
 6008
 6009            editor.refresh_edit_prediction(true, false, window, cx);
 6010        });
 6011        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 6012
 6013        let show_new_completions_on_confirm = completion
 6014            .confirm
 6015            .as_ref()
 6016            .is_some_and(|confirm| confirm(intent, window, cx));
 6017        if show_new_completions_on_confirm {
 6018            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6019        }
 6020
 6021        let provider = self.completion_provider.as_ref()?;
 6022        drop(completion);
 6023        let apply_edits = provider.apply_additional_edits_for_completion(
 6024            buffer_handle,
 6025            completions_menu.completions.clone(),
 6026            candidate_id,
 6027            true,
 6028            cx,
 6029        );
 6030
 6031        let editor_settings = EditorSettings::get_global(cx);
 6032        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6033            // After the code completion is finished, users often want to know what signatures are needed.
 6034            // so we should automatically call signature_help
 6035            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6036        }
 6037
 6038        Some(cx.foreground_executor().spawn(async move {
 6039            apply_edits.await?;
 6040            Ok(())
 6041        }))
 6042    }
 6043
 6044    pub fn toggle_code_actions(
 6045        &mut self,
 6046        action: &ToggleCodeActions,
 6047        window: &mut Window,
 6048        cx: &mut Context<Self>,
 6049    ) {
 6050        let quick_launch = action.quick_launch;
 6051        let mut context_menu = self.context_menu.borrow_mut();
 6052        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6053            if code_actions.deployed_from == action.deployed_from {
 6054                // Toggle if we're selecting the same one
 6055                *context_menu = None;
 6056                cx.notify();
 6057                return;
 6058            } else {
 6059                // Otherwise, clear it and start a new one
 6060                *context_menu = None;
 6061                cx.notify();
 6062            }
 6063        }
 6064        drop(context_menu);
 6065        let snapshot = self.snapshot(window, cx);
 6066        let deployed_from = action.deployed_from.clone();
 6067        let action = action.clone();
 6068        self.completion_tasks.clear();
 6069        self.discard_edit_prediction(false, cx);
 6070
 6071        let multibuffer_point = match &action.deployed_from {
 6072            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6073                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6074            }
 6075            _ => self.selections.newest::<Point>(cx).head(),
 6076        };
 6077        let Some((buffer, buffer_row)) = snapshot
 6078            .buffer_snapshot
 6079            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6080            .and_then(|(buffer_snapshot, range)| {
 6081                self.buffer()
 6082                    .read(cx)
 6083                    .buffer(buffer_snapshot.remote_id())
 6084                    .map(|buffer| (buffer, range.start.row))
 6085            })
 6086        else {
 6087            return;
 6088        };
 6089        let buffer_id = buffer.read(cx).remote_id();
 6090        let tasks = self
 6091            .tasks
 6092            .get(&(buffer_id, buffer_row))
 6093            .map(|t| Arc::new(t.to_owned()));
 6094
 6095        if !self.focus_handle.is_focused(window) {
 6096            return;
 6097        }
 6098        let project = self.project.clone();
 6099
 6100        let code_actions_task = match deployed_from {
 6101            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6102            _ => self.code_actions(buffer_row, window, cx),
 6103        };
 6104
 6105        let runnable_task = match deployed_from {
 6106            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6107            _ => {
 6108                let mut task_context_task = Task::ready(None);
 6109                if let Some(tasks) = &tasks
 6110                    && let Some(project) = project
 6111                {
 6112                    task_context_task =
 6113                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6114                }
 6115
 6116                cx.spawn_in(window, {
 6117                    let buffer = buffer.clone();
 6118                    async move |editor, cx| {
 6119                        let task_context = task_context_task.await;
 6120
 6121                        let resolved_tasks =
 6122                            tasks
 6123                                .zip(task_context.clone())
 6124                                .map(|(tasks, task_context)| ResolvedTasks {
 6125                                    templates: tasks.resolve(&task_context).collect(),
 6126                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6127                                        multibuffer_point.row,
 6128                                        tasks.column,
 6129                                    )),
 6130                                });
 6131                        let debug_scenarios = editor
 6132                            .update(cx, |editor, cx| {
 6133                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6134                            })?
 6135                            .await;
 6136                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6137                    }
 6138                })
 6139            }
 6140        };
 6141
 6142        cx.spawn_in(window, async move |editor, cx| {
 6143            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6144            let code_actions = code_actions_task.await;
 6145            let spawn_straight_away = quick_launch
 6146                && resolved_tasks
 6147                    .as_ref()
 6148                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6149                && code_actions
 6150                    .as_ref()
 6151                    .is_none_or(|actions| actions.is_empty())
 6152                && debug_scenarios.is_empty();
 6153
 6154            editor.update_in(cx, |editor, window, cx| {
 6155                crate::hover_popover::hide_hover(editor, cx);
 6156                let actions = CodeActionContents::new(
 6157                    resolved_tasks,
 6158                    code_actions,
 6159                    debug_scenarios,
 6160                    task_context.unwrap_or_default(),
 6161                );
 6162
 6163                // Don't show the menu if there are no actions available
 6164                if actions.is_empty() {
 6165                    cx.notify();
 6166                    return Task::ready(Ok(()));
 6167                }
 6168
 6169                *editor.context_menu.borrow_mut() =
 6170                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6171                        buffer,
 6172                        actions,
 6173                        selected_item: Default::default(),
 6174                        scroll_handle: UniformListScrollHandle::default(),
 6175                        deployed_from,
 6176                    }));
 6177                cx.notify();
 6178                if spawn_straight_away
 6179                    && let Some(task) = editor.confirm_code_action(
 6180                        &ConfirmCodeAction { item_ix: Some(0) },
 6181                        window,
 6182                        cx,
 6183                    )
 6184                {
 6185                    return task;
 6186                }
 6187
 6188                Task::ready(Ok(()))
 6189            })
 6190        })
 6191        .detach_and_log_err(cx);
 6192    }
 6193
 6194    fn debug_scenarios(
 6195        &mut self,
 6196        resolved_tasks: &Option<ResolvedTasks>,
 6197        buffer: &Entity<Buffer>,
 6198        cx: &mut App,
 6199    ) -> Task<Vec<task::DebugScenario>> {
 6200        maybe!({
 6201            let project = self.project()?;
 6202            let dap_store = project.read(cx).dap_store();
 6203            let mut scenarios = vec![];
 6204            let resolved_tasks = resolved_tasks.as_ref()?;
 6205            let buffer = buffer.read(cx);
 6206            let language = buffer.language()?;
 6207            let file = buffer.file();
 6208            let debug_adapter = language_settings(language.name().into(), file, cx)
 6209                .debuggers
 6210                .first()
 6211                .map(SharedString::from)
 6212                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6213
 6214            dap_store.update(cx, |dap_store, cx| {
 6215                for (_, task) in &resolved_tasks.templates {
 6216                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6217                        task.original_task().clone(),
 6218                        debug_adapter.clone().into(),
 6219                        task.display_label().to_owned().into(),
 6220                        cx,
 6221                    );
 6222                    scenarios.push(maybe_scenario);
 6223                }
 6224            });
 6225            Some(cx.background_spawn(async move {
 6226                futures::future::join_all(scenarios)
 6227                    .await
 6228                    .into_iter()
 6229                    .flatten()
 6230                    .collect::<Vec<_>>()
 6231            }))
 6232        })
 6233        .unwrap_or_else(|| Task::ready(vec![]))
 6234    }
 6235
 6236    fn code_actions(
 6237        &mut self,
 6238        buffer_row: u32,
 6239        window: &mut Window,
 6240        cx: &mut Context<Self>,
 6241    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6242        let mut task = self.code_actions_task.take();
 6243        cx.spawn_in(window, async move |editor, cx| {
 6244            while let Some(prev_task) = task {
 6245                prev_task.await.log_err();
 6246                task = editor
 6247                    .update(cx, |this, _| this.code_actions_task.take())
 6248                    .ok()?;
 6249            }
 6250
 6251            editor
 6252                .update(cx, |editor, cx| {
 6253                    editor
 6254                        .available_code_actions
 6255                        .clone()
 6256                        .and_then(|(location, code_actions)| {
 6257                            let snapshot = location.buffer.read(cx).snapshot();
 6258                            let point_range = location.range.to_point(&snapshot);
 6259                            let point_range = point_range.start.row..=point_range.end.row;
 6260                            if point_range.contains(&buffer_row) {
 6261                                Some(code_actions)
 6262                            } else {
 6263                                None
 6264                            }
 6265                        })
 6266                })
 6267                .ok()
 6268                .flatten()
 6269        })
 6270    }
 6271
 6272    pub fn confirm_code_action(
 6273        &mut self,
 6274        action: &ConfirmCodeAction,
 6275        window: &mut Window,
 6276        cx: &mut Context<Self>,
 6277    ) -> Option<Task<Result<()>>> {
 6278        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6279
 6280        let actions_menu =
 6281            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6282                menu
 6283            } else {
 6284                return None;
 6285            };
 6286
 6287        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6288        let action = actions_menu.actions.get(action_ix)?;
 6289        let title = action.label();
 6290        let buffer = actions_menu.buffer;
 6291        let workspace = self.workspace()?;
 6292
 6293        match action {
 6294            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6295                workspace.update(cx, |workspace, cx| {
 6296                    workspace.schedule_resolved_task(
 6297                        task_source_kind,
 6298                        resolved_task,
 6299                        false,
 6300                        window,
 6301                        cx,
 6302                    );
 6303
 6304                    Some(Task::ready(Ok(())))
 6305                })
 6306            }
 6307            CodeActionsItem::CodeAction {
 6308                excerpt_id,
 6309                action,
 6310                provider,
 6311            } => {
 6312                let apply_code_action =
 6313                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6314                let workspace = workspace.downgrade();
 6315                Some(cx.spawn_in(window, async move |editor, cx| {
 6316                    let project_transaction = apply_code_action.await?;
 6317                    Self::open_project_transaction(
 6318                        &editor,
 6319                        workspace,
 6320                        project_transaction,
 6321                        title,
 6322                        cx,
 6323                    )
 6324                    .await
 6325                }))
 6326            }
 6327            CodeActionsItem::DebugScenario(scenario) => {
 6328                let context = actions_menu.actions.context;
 6329
 6330                workspace.update(cx, |workspace, cx| {
 6331                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6332                    workspace.start_debug_session(
 6333                        scenario,
 6334                        context,
 6335                        Some(buffer),
 6336                        None,
 6337                        window,
 6338                        cx,
 6339                    );
 6340                });
 6341                Some(Task::ready(Ok(())))
 6342            }
 6343        }
 6344    }
 6345
 6346    pub async fn open_project_transaction(
 6347        editor: &WeakEntity<Editor>,
 6348        workspace: WeakEntity<Workspace>,
 6349        transaction: ProjectTransaction,
 6350        title: String,
 6351        cx: &mut AsyncWindowContext,
 6352    ) -> Result<()> {
 6353        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6354        cx.update(|_, cx| {
 6355            entries.sort_unstable_by_key(|(buffer, _)| {
 6356                buffer.read(cx).file().map(|f| f.path().clone())
 6357            });
 6358        })?;
 6359
 6360        // If the project transaction's edits are all contained within this editor, then
 6361        // avoid opening a new editor to display them.
 6362
 6363        if let Some((buffer, transaction)) = entries.first() {
 6364            if entries.len() == 1 {
 6365                let excerpt = editor.update(cx, |editor, cx| {
 6366                    editor
 6367                        .buffer()
 6368                        .read(cx)
 6369                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6370                })?;
 6371                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6372                    && excerpted_buffer == *buffer
 6373                {
 6374                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6375                        let excerpt_range = excerpt_range.to_offset(buffer);
 6376                        buffer
 6377                            .edited_ranges_for_transaction::<usize>(transaction)
 6378                            .all(|range| {
 6379                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6380                            })
 6381                    })?;
 6382
 6383                    if all_edits_within_excerpt {
 6384                        return Ok(());
 6385                    }
 6386                }
 6387            }
 6388        } else {
 6389            return Ok(());
 6390        }
 6391
 6392        let mut ranges_to_highlight = Vec::new();
 6393        let excerpt_buffer = cx.new(|cx| {
 6394            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6395            for (buffer_handle, transaction) in &entries {
 6396                let edited_ranges = buffer_handle
 6397                    .read(cx)
 6398                    .edited_ranges_for_transaction::<Point>(transaction)
 6399                    .collect::<Vec<_>>();
 6400                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6401                    PathKey::for_buffer(buffer_handle, cx),
 6402                    buffer_handle.clone(),
 6403                    edited_ranges,
 6404                    multibuffer_context_lines(cx),
 6405                    cx,
 6406                );
 6407
 6408                ranges_to_highlight.extend(ranges);
 6409            }
 6410            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6411            multibuffer
 6412        })?;
 6413
 6414        workspace.update_in(cx, |workspace, window, cx| {
 6415            let project = workspace.project().clone();
 6416            let editor =
 6417                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6418            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6419            editor.update(cx, |editor, cx| {
 6420                editor.highlight_background::<Self>(
 6421                    &ranges_to_highlight,
 6422                    |theme| theme.colors().editor_highlighted_line_background,
 6423                    cx,
 6424                );
 6425            });
 6426        })?;
 6427
 6428        Ok(())
 6429    }
 6430
 6431    pub fn clear_code_action_providers(&mut self) {
 6432        self.code_action_providers.clear();
 6433        self.available_code_actions.take();
 6434    }
 6435
 6436    pub fn add_code_action_provider(
 6437        &mut self,
 6438        provider: Rc<dyn CodeActionProvider>,
 6439        window: &mut Window,
 6440        cx: &mut Context<Self>,
 6441    ) {
 6442        if self
 6443            .code_action_providers
 6444            .iter()
 6445            .any(|existing_provider| existing_provider.id() == provider.id())
 6446        {
 6447            return;
 6448        }
 6449
 6450        self.code_action_providers.push(provider);
 6451        self.refresh_code_actions(window, cx);
 6452    }
 6453
 6454    pub fn remove_code_action_provider(
 6455        &mut self,
 6456        id: Arc<str>,
 6457        window: &mut Window,
 6458        cx: &mut Context<Self>,
 6459    ) {
 6460        self.code_action_providers
 6461            .retain(|provider| provider.id() != id);
 6462        self.refresh_code_actions(window, cx);
 6463    }
 6464
 6465    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6466        !self.code_action_providers.is_empty()
 6467            && EditorSettings::get_global(cx).toolbar.code_actions
 6468    }
 6469
 6470    pub fn has_available_code_actions(&self) -> bool {
 6471        self.available_code_actions
 6472            .as_ref()
 6473            .is_some_and(|(_, actions)| !actions.is_empty())
 6474    }
 6475
 6476    fn render_inline_code_actions(
 6477        &self,
 6478        icon_size: ui::IconSize,
 6479        display_row: DisplayRow,
 6480        is_active: bool,
 6481        cx: &mut Context<Self>,
 6482    ) -> AnyElement {
 6483        let show_tooltip = !self.context_menu_visible();
 6484        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6485            .icon_size(icon_size)
 6486            .shape(ui::IconButtonShape::Square)
 6487            .icon_color(ui::Color::Hidden)
 6488            .toggle_state(is_active)
 6489            .when(show_tooltip, |this| {
 6490                this.tooltip({
 6491                    let focus_handle = self.focus_handle.clone();
 6492                    move |window, cx| {
 6493                        Tooltip::for_action_in(
 6494                            "Toggle Code Actions",
 6495                            &ToggleCodeActions {
 6496                                deployed_from: None,
 6497                                quick_launch: false,
 6498                            },
 6499                            &focus_handle,
 6500                            window,
 6501                            cx,
 6502                        )
 6503                    }
 6504                })
 6505            })
 6506            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6507                window.focus(&editor.focus_handle(cx));
 6508                editor.toggle_code_actions(
 6509                    &crate::actions::ToggleCodeActions {
 6510                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6511                            display_row,
 6512                        )),
 6513                        quick_launch: false,
 6514                    },
 6515                    window,
 6516                    cx,
 6517                );
 6518            }))
 6519            .into_any_element()
 6520    }
 6521
 6522    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6523        &self.context_menu
 6524    }
 6525
 6526    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6527        let newest_selection = self.selections.newest_anchor().clone();
 6528        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6529        let buffer = self.buffer.read(cx);
 6530        if newest_selection.head().diff_base_anchor.is_some() {
 6531            return None;
 6532        }
 6533        let (start_buffer, start) =
 6534            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6535        let (end_buffer, end) =
 6536            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6537        if start_buffer != end_buffer {
 6538            return None;
 6539        }
 6540
 6541        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6542            cx.background_executor()
 6543                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6544                .await;
 6545
 6546            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6547                let providers = this.code_action_providers.clone();
 6548                let tasks = this
 6549                    .code_action_providers
 6550                    .iter()
 6551                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6552                    .collect::<Vec<_>>();
 6553                (providers, tasks)
 6554            })?;
 6555
 6556            let mut actions = Vec::new();
 6557            for (provider, provider_actions) in
 6558                providers.into_iter().zip(future::join_all(tasks).await)
 6559            {
 6560                if let Some(provider_actions) = provider_actions.log_err() {
 6561                    actions.extend(provider_actions.into_iter().map(|action| {
 6562                        AvailableCodeAction {
 6563                            excerpt_id: newest_selection.start.excerpt_id,
 6564                            action,
 6565                            provider: provider.clone(),
 6566                        }
 6567                    }));
 6568                }
 6569            }
 6570
 6571            this.update(cx, |this, cx| {
 6572                this.available_code_actions = if actions.is_empty() {
 6573                    None
 6574                } else {
 6575                    Some((
 6576                        Location {
 6577                            buffer: start_buffer,
 6578                            range: start..end,
 6579                        },
 6580                        actions.into(),
 6581                    ))
 6582                };
 6583                cx.notify();
 6584            })
 6585        }));
 6586        None
 6587    }
 6588
 6589    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6590        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6591            self.show_git_blame_inline = false;
 6592
 6593            self.show_git_blame_inline_delay_task =
 6594                Some(cx.spawn_in(window, async move |this, cx| {
 6595                    cx.background_executor().timer(delay).await;
 6596
 6597                    this.update(cx, |this, cx| {
 6598                        this.show_git_blame_inline = true;
 6599                        cx.notify();
 6600                    })
 6601                    .log_err();
 6602                }));
 6603        }
 6604    }
 6605
 6606    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6607        let snapshot = self.snapshot(window, cx);
 6608        let cursor = self.selections.newest::<Point>(cx).head();
 6609        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6610        else {
 6611            return;
 6612        };
 6613
 6614        let Some(blame) = self.blame.as_ref() else {
 6615            return;
 6616        };
 6617
 6618        let row_info = RowInfo {
 6619            buffer_id: Some(buffer.remote_id()),
 6620            buffer_row: Some(point.row),
 6621            ..Default::default()
 6622        };
 6623        let Some(blame_entry) = blame
 6624            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6625            .flatten()
 6626        else {
 6627            return;
 6628        };
 6629
 6630        let anchor = self.selections.newest_anchor().head();
 6631        let position = self.to_pixel_point(anchor, &snapshot, window);
 6632        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6633            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6634        };
 6635    }
 6636
 6637    fn show_blame_popover(
 6638        &mut self,
 6639        blame_entry: &BlameEntry,
 6640        position: gpui::Point<Pixels>,
 6641        ignore_timeout: bool,
 6642        cx: &mut Context<Self>,
 6643    ) {
 6644        if let Some(state) = &mut self.inline_blame_popover {
 6645            state.hide_task.take();
 6646        } else {
 6647            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6648            let blame_entry = blame_entry.clone();
 6649            let show_task = cx.spawn(async move |editor, cx| {
 6650                if !ignore_timeout {
 6651                    cx.background_executor()
 6652                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6653                        .await;
 6654                }
 6655                editor
 6656                    .update(cx, |editor, cx| {
 6657                        editor.inline_blame_popover_show_task.take();
 6658                        let Some(blame) = editor.blame.as_ref() else {
 6659                            return;
 6660                        };
 6661                        let blame = blame.read(cx);
 6662                        let details = blame.details_for_entry(&blame_entry);
 6663                        let markdown = cx.new(|cx| {
 6664                            Markdown::new(
 6665                                details
 6666                                    .as_ref()
 6667                                    .map(|message| message.message.clone())
 6668                                    .unwrap_or_default(),
 6669                                None,
 6670                                None,
 6671                                cx,
 6672                            )
 6673                        });
 6674                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6675                            position,
 6676                            hide_task: None,
 6677                            popover_bounds: None,
 6678                            popover_state: InlineBlamePopoverState {
 6679                                scroll_handle: ScrollHandle::new(),
 6680                                commit_message: details,
 6681                                markdown,
 6682                            },
 6683                            keyboard_grace: ignore_timeout,
 6684                        });
 6685                        cx.notify();
 6686                    })
 6687                    .ok();
 6688            });
 6689            self.inline_blame_popover_show_task = Some(show_task);
 6690        }
 6691    }
 6692
 6693    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6694        self.inline_blame_popover_show_task.take();
 6695        if let Some(state) = &mut self.inline_blame_popover {
 6696            let hide_task = cx.spawn(async move |editor, cx| {
 6697                cx.background_executor()
 6698                    .timer(std::time::Duration::from_millis(100))
 6699                    .await;
 6700                editor
 6701                    .update(cx, |editor, cx| {
 6702                        editor.inline_blame_popover.take();
 6703                        cx.notify();
 6704                    })
 6705                    .ok();
 6706            });
 6707            state.hide_task = Some(hide_task);
 6708        }
 6709    }
 6710
 6711    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6712        if self.pending_rename.is_some() {
 6713            return None;
 6714        }
 6715
 6716        let provider = self.semantics_provider.clone()?;
 6717        let buffer = self.buffer.read(cx);
 6718        let newest_selection = self.selections.newest_anchor().clone();
 6719        let cursor_position = newest_selection.head();
 6720        let (cursor_buffer, cursor_buffer_position) =
 6721            buffer.text_anchor_for_position(cursor_position, cx)?;
 6722        let (tail_buffer, tail_buffer_position) =
 6723            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6724        if cursor_buffer != tail_buffer {
 6725            return None;
 6726        }
 6727
 6728        let snapshot = cursor_buffer.read(cx).snapshot();
 6729        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6730        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6731        if start_word_range != end_word_range {
 6732            self.document_highlights_task.take();
 6733            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6734            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6735            return None;
 6736        }
 6737
 6738        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6739        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6740            cx.background_executor()
 6741                .timer(Duration::from_millis(debounce))
 6742                .await;
 6743
 6744            let highlights = if let Some(highlights) = cx
 6745                .update(|cx| {
 6746                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6747                })
 6748                .ok()
 6749                .flatten()
 6750            {
 6751                highlights.await.log_err()
 6752            } else {
 6753                None
 6754            };
 6755
 6756            if let Some(highlights) = highlights {
 6757                this.update(cx, |this, cx| {
 6758                    if this.pending_rename.is_some() {
 6759                        return;
 6760                    }
 6761
 6762                    let buffer = this.buffer.read(cx);
 6763                    if buffer
 6764                        .text_anchor_for_position(cursor_position, cx)
 6765                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6766                    {
 6767                        return;
 6768                    }
 6769
 6770                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6771                    let mut write_ranges = Vec::new();
 6772                    let mut read_ranges = Vec::new();
 6773                    for highlight in highlights {
 6774                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6775                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6776                        {
 6777                            let start = highlight
 6778                                .range
 6779                                .start
 6780                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6781                            let end = highlight
 6782                                .range
 6783                                .end
 6784                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6785                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6786                                continue;
 6787                            }
 6788
 6789                            let range = Anchor {
 6790                                buffer_id: Some(buffer_id),
 6791                                excerpt_id,
 6792                                text_anchor: start,
 6793                                diff_base_anchor: None,
 6794                            }..Anchor {
 6795                                buffer_id: Some(buffer_id),
 6796                                excerpt_id,
 6797                                text_anchor: end,
 6798                                diff_base_anchor: None,
 6799                            };
 6800                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6801                                write_ranges.push(range);
 6802                            } else {
 6803                                read_ranges.push(range);
 6804                            }
 6805                        }
 6806                    }
 6807
 6808                    this.highlight_background::<DocumentHighlightRead>(
 6809                        &read_ranges,
 6810                        |theme| theme.colors().editor_document_highlight_read_background,
 6811                        cx,
 6812                    );
 6813                    this.highlight_background::<DocumentHighlightWrite>(
 6814                        &write_ranges,
 6815                        |theme| theme.colors().editor_document_highlight_write_background,
 6816                        cx,
 6817                    );
 6818                    cx.notify();
 6819                })
 6820                .log_err();
 6821            }
 6822        }));
 6823        None
 6824    }
 6825
 6826    fn prepare_highlight_query_from_selection(
 6827        &mut self,
 6828        cx: &mut Context<Editor>,
 6829    ) -> Option<(String, Range<Anchor>)> {
 6830        if matches!(self.mode, EditorMode::SingleLine) {
 6831            return None;
 6832        }
 6833        if !EditorSettings::get_global(cx).selection_highlight {
 6834            return None;
 6835        }
 6836        if self.selections.count() != 1 || self.selections.line_mode {
 6837            return None;
 6838        }
 6839        let selection = self.selections.newest::<Point>(cx);
 6840        if selection.is_empty() || selection.start.row != selection.end.row {
 6841            return None;
 6842        }
 6843        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6844        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6845        let query = multi_buffer_snapshot
 6846            .text_for_range(selection_anchor_range.clone())
 6847            .collect::<String>();
 6848        if query.trim().is_empty() {
 6849            return None;
 6850        }
 6851        Some((query, selection_anchor_range))
 6852    }
 6853
 6854    fn update_selection_occurrence_highlights(
 6855        &mut self,
 6856        query_text: String,
 6857        query_range: Range<Anchor>,
 6858        multi_buffer_range_to_query: Range<Point>,
 6859        use_debounce: bool,
 6860        window: &mut Window,
 6861        cx: &mut Context<Editor>,
 6862    ) -> Task<()> {
 6863        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6864        cx.spawn_in(window, async move |editor, cx| {
 6865            if use_debounce {
 6866                cx.background_executor()
 6867                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6868                    .await;
 6869            }
 6870            let match_task = cx.background_spawn(async move {
 6871                let buffer_ranges = multi_buffer_snapshot
 6872                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6873                    .into_iter()
 6874                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6875                let mut match_ranges = Vec::new();
 6876                let Ok(regex) = project::search::SearchQuery::text(
 6877                    query_text.clone(),
 6878                    false,
 6879                    false,
 6880                    false,
 6881                    Default::default(),
 6882                    Default::default(),
 6883                    false,
 6884                    None,
 6885                ) else {
 6886                    return Vec::default();
 6887                };
 6888                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6889                    match_ranges.extend(
 6890                        regex
 6891                            .search(buffer_snapshot, Some(search_range.clone()))
 6892                            .await
 6893                            .into_iter()
 6894                            .filter_map(|match_range| {
 6895                                let match_start = buffer_snapshot
 6896                                    .anchor_after(search_range.start + match_range.start);
 6897                                let match_end = buffer_snapshot
 6898                                    .anchor_before(search_range.start + match_range.end);
 6899                                let match_anchor_range = Anchor::range_in_buffer(
 6900                                    excerpt_id,
 6901                                    buffer_snapshot.remote_id(),
 6902                                    match_start..match_end,
 6903                                );
 6904                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6905                            }),
 6906                    );
 6907                }
 6908                match_ranges
 6909            });
 6910            let match_ranges = match_task.await;
 6911            editor
 6912                .update_in(cx, |editor, _, cx| {
 6913                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6914                    if !match_ranges.is_empty() {
 6915                        editor.highlight_background::<SelectedTextHighlight>(
 6916                            &match_ranges,
 6917                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6918                            cx,
 6919                        )
 6920                    }
 6921                })
 6922                .log_err();
 6923        })
 6924    }
 6925
 6926    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6927        struct NewlineFold;
 6928        let type_id = std::any::TypeId::of::<NewlineFold>();
 6929        if !self.mode.is_single_line() {
 6930            return;
 6931        }
 6932        let snapshot = self.snapshot(window, cx);
 6933        if snapshot.buffer_snapshot.max_point().row == 0 {
 6934            return;
 6935        }
 6936        let task = cx.background_spawn(async move {
 6937            let new_newlines = snapshot
 6938                .buffer_chars_at(0)
 6939                .filter_map(|(c, i)| {
 6940                    if c == '\n' {
 6941                        Some(
 6942                            snapshot.buffer_snapshot.anchor_after(i)
 6943                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6944                        )
 6945                    } else {
 6946                        None
 6947                    }
 6948                })
 6949                .collect::<Vec<_>>();
 6950            let existing_newlines = snapshot
 6951                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6952                .filter_map(|fold| {
 6953                    if fold.placeholder.type_tag == Some(type_id) {
 6954                        Some(fold.range.start..fold.range.end)
 6955                    } else {
 6956                        None
 6957                    }
 6958                })
 6959                .collect::<Vec<_>>();
 6960
 6961            (new_newlines, existing_newlines)
 6962        });
 6963        self.folding_newlines = cx.spawn(async move |this, cx| {
 6964            let (new_newlines, existing_newlines) = task.await;
 6965            if new_newlines == existing_newlines {
 6966                return;
 6967            }
 6968            let placeholder = FoldPlaceholder {
 6969                render: Arc::new(move |_, _, cx| {
 6970                    div()
 6971                        .bg(cx.theme().status().hint_background)
 6972                        .border_b_1()
 6973                        .size_full()
 6974                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6975                        .border_color(cx.theme().status().hint)
 6976                        .child("\\n")
 6977                        .into_any()
 6978                }),
 6979                constrain_width: false,
 6980                merge_adjacent: false,
 6981                type_tag: Some(type_id),
 6982            };
 6983            let creases = new_newlines
 6984                .into_iter()
 6985                .map(|range| Crease::simple(range, placeholder.clone()))
 6986                .collect();
 6987            this.update(cx, |this, cx| {
 6988                this.display_map.update(cx, |display_map, cx| {
 6989                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6990                    display_map.fold(creases, cx);
 6991                });
 6992            })
 6993            .ok();
 6994        });
 6995    }
 6996
 6997    fn refresh_selected_text_highlights(
 6998        &mut self,
 6999        on_buffer_edit: bool,
 7000        window: &mut Window,
 7001        cx: &mut Context<Editor>,
 7002    ) {
 7003        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7004        else {
 7005            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7006            self.quick_selection_highlight_task.take();
 7007            self.debounced_selection_highlight_task.take();
 7008            return;
 7009        };
 7010        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7011        if on_buffer_edit
 7012            || self
 7013                .quick_selection_highlight_task
 7014                .as_ref()
 7015                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7016        {
 7017            let multi_buffer_visible_start = self
 7018                .scroll_manager
 7019                .anchor()
 7020                .anchor
 7021                .to_point(&multi_buffer_snapshot);
 7022            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7023                multi_buffer_visible_start
 7024                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7025                Bias::Left,
 7026            );
 7027            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7028            self.quick_selection_highlight_task = Some((
 7029                query_range.clone(),
 7030                self.update_selection_occurrence_highlights(
 7031                    query_text.clone(),
 7032                    query_range.clone(),
 7033                    multi_buffer_visible_range,
 7034                    false,
 7035                    window,
 7036                    cx,
 7037                ),
 7038            ));
 7039        }
 7040        if on_buffer_edit
 7041            || self
 7042                .debounced_selection_highlight_task
 7043                .as_ref()
 7044                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7045        {
 7046            let multi_buffer_start = multi_buffer_snapshot
 7047                .anchor_before(0)
 7048                .to_point(&multi_buffer_snapshot);
 7049            let multi_buffer_end = multi_buffer_snapshot
 7050                .anchor_after(multi_buffer_snapshot.len())
 7051                .to_point(&multi_buffer_snapshot);
 7052            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7053            self.debounced_selection_highlight_task = Some((
 7054                query_range.clone(),
 7055                self.update_selection_occurrence_highlights(
 7056                    query_text,
 7057                    query_range,
 7058                    multi_buffer_full_range,
 7059                    true,
 7060                    window,
 7061                    cx,
 7062                ),
 7063            ));
 7064        }
 7065    }
 7066
 7067    pub fn refresh_edit_prediction(
 7068        &mut self,
 7069        debounce: bool,
 7070        user_requested: bool,
 7071        window: &mut Window,
 7072        cx: &mut Context<Self>,
 7073    ) -> Option<()> {
 7074        if DisableAiSettings::get_global(cx).disable_ai {
 7075            return None;
 7076        }
 7077
 7078        let provider = self.edit_prediction_provider()?;
 7079        let cursor = self.selections.newest_anchor().head();
 7080        let (buffer, cursor_buffer_position) =
 7081            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7082
 7083        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7084            self.discard_edit_prediction(false, cx);
 7085            return None;
 7086        }
 7087
 7088        if !user_requested
 7089            && (!self.should_show_edit_predictions()
 7090                || !self.is_focused(window)
 7091                || buffer.read(cx).is_empty())
 7092        {
 7093            self.discard_edit_prediction(false, cx);
 7094            return None;
 7095        }
 7096
 7097        self.update_visible_edit_prediction(window, cx);
 7098        provider.refresh(
 7099            self.project.clone(),
 7100            buffer,
 7101            cursor_buffer_position,
 7102            debounce,
 7103            cx,
 7104        );
 7105        Some(())
 7106    }
 7107
 7108    fn show_edit_predictions_in_menu(&self) -> bool {
 7109        match self.edit_prediction_settings {
 7110            EditPredictionSettings::Disabled => false,
 7111            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7112        }
 7113    }
 7114
 7115    pub fn edit_predictions_enabled(&self) -> bool {
 7116        match self.edit_prediction_settings {
 7117            EditPredictionSettings::Disabled => false,
 7118            EditPredictionSettings::Enabled { .. } => true,
 7119        }
 7120    }
 7121
 7122    fn edit_prediction_requires_modifier(&self) -> bool {
 7123        match self.edit_prediction_settings {
 7124            EditPredictionSettings::Disabled => false,
 7125            EditPredictionSettings::Enabled {
 7126                preview_requires_modifier,
 7127                ..
 7128            } => preview_requires_modifier,
 7129        }
 7130    }
 7131
 7132    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7133        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7134            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7135            self.discard_edit_prediction(false, cx);
 7136        } else {
 7137            let selection = self.selections.newest_anchor();
 7138            let cursor = selection.head();
 7139
 7140            if let Some((buffer, cursor_buffer_position)) =
 7141                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7142            {
 7143                self.edit_prediction_settings =
 7144                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7145            }
 7146        }
 7147    }
 7148
 7149    fn edit_prediction_settings_at_position(
 7150        &self,
 7151        buffer: &Entity<Buffer>,
 7152        buffer_position: language::Anchor,
 7153        cx: &App,
 7154    ) -> EditPredictionSettings {
 7155        if !self.mode.is_full()
 7156            || !self.show_edit_predictions_override.unwrap_or(true)
 7157            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7158        {
 7159            return EditPredictionSettings::Disabled;
 7160        }
 7161
 7162        let buffer = buffer.read(cx);
 7163
 7164        let file = buffer.file();
 7165
 7166        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7167            return EditPredictionSettings::Disabled;
 7168        };
 7169
 7170        let by_provider = matches!(
 7171            self.menu_edit_predictions_policy,
 7172            MenuEditPredictionsPolicy::ByProvider
 7173        );
 7174
 7175        let show_in_menu = by_provider
 7176            && self
 7177                .edit_prediction_provider
 7178                .as_ref()
 7179                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7180
 7181        let preview_requires_modifier =
 7182            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7183
 7184        EditPredictionSettings::Enabled {
 7185            show_in_menu,
 7186            preview_requires_modifier,
 7187        }
 7188    }
 7189
 7190    fn should_show_edit_predictions(&self) -> bool {
 7191        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7192    }
 7193
 7194    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7195        matches!(
 7196            self.edit_prediction_preview,
 7197            EditPredictionPreview::Active { .. }
 7198        )
 7199    }
 7200
 7201    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7202        let cursor = self.selections.newest_anchor().head();
 7203        if let Some((buffer, cursor_position)) =
 7204            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7205        {
 7206            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7207        } else {
 7208            false
 7209        }
 7210    }
 7211
 7212    pub fn supports_minimap(&self, cx: &App) -> bool {
 7213        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7214    }
 7215
 7216    fn edit_predictions_enabled_in_buffer(
 7217        &self,
 7218        buffer: &Entity<Buffer>,
 7219        buffer_position: language::Anchor,
 7220        cx: &App,
 7221    ) -> bool {
 7222        maybe!({
 7223            if self.read_only(cx) {
 7224                return Some(false);
 7225            }
 7226            let provider = self.edit_prediction_provider()?;
 7227            if !provider.is_enabled(buffer, buffer_position, cx) {
 7228                return Some(false);
 7229            }
 7230            let buffer = buffer.read(cx);
 7231            let Some(file) = buffer.file() else {
 7232                return Some(true);
 7233            };
 7234            let settings = all_language_settings(Some(file), cx);
 7235            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7236        })
 7237        .unwrap_or(false)
 7238    }
 7239
 7240    fn cycle_edit_prediction(
 7241        &mut self,
 7242        direction: Direction,
 7243        window: &mut Window,
 7244        cx: &mut Context<Self>,
 7245    ) -> Option<()> {
 7246        let provider = self.edit_prediction_provider()?;
 7247        let cursor = self.selections.newest_anchor().head();
 7248        let (buffer, cursor_buffer_position) =
 7249            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7250        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7251            return None;
 7252        }
 7253
 7254        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7255        self.update_visible_edit_prediction(window, cx);
 7256
 7257        Some(())
 7258    }
 7259
 7260    pub fn show_edit_prediction(
 7261        &mut self,
 7262        _: &ShowEditPrediction,
 7263        window: &mut Window,
 7264        cx: &mut Context<Self>,
 7265    ) {
 7266        if !self.has_active_edit_prediction() {
 7267            self.refresh_edit_prediction(false, true, window, cx);
 7268            return;
 7269        }
 7270
 7271        self.update_visible_edit_prediction(window, cx);
 7272    }
 7273
 7274    pub fn display_cursor_names(
 7275        &mut self,
 7276        _: &DisplayCursorNames,
 7277        window: &mut Window,
 7278        cx: &mut Context<Self>,
 7279    ) {
 7280        self.show_cursor_names(window, cx);
 7281    }
 7282
 7283    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7284        self.show_cursor_names = true;
 7285        cx.notify();
 7286        cx.spawn_in(window, async move |this, cx| {
 7287            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7288            this.update(cx, |this, cx| {
 7289                this.show_cursor_names = false;
 7290                cx.notify()
 7291            })
 7292            .ok()
 7293        })
 7294        .detach();
 7295    }
 7296
 7297    pub fn next_edit_prediction(
 7298        &mut self,
 7299        _: &NextEditPrediction,
 7300        window: &mut Window,
 7301        cx: &mut Context<Self>,
 7302    ) {
 7303        if self.has_active_edit_prediction() {
 7304            self.cycle_edit_prediction(Direction::Next, window, cx);
 7305        } else {
 7306            let is_copilot_disabled = self
 7307                .refresh_edit_prediction(false, true, window, cx)
 7308                .is_none();
 7309            if is_copilot_disabled {
 7310                cx.propagate();
 7311            }
 7312        }
 7313    }
 7314
 7315    pub fn previous_edit_prediction(
 7316        &mut self,
 7317        _: &PreviousEditPrediction,
 7318        window: &mut Window,
 7319        cx: &mut Context<Self>,
 7320    ) {
 7321        if self.has_active_edit_prediction() {
 7322            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7323        } else {
 7324            let is_copilot_disabled = self
 7325                .refresh_edit_prediction(false, true, window, cx)
 7326                .is_none();
 7327            if is_copilot_disabled {
 7328                cx.propagate();
 7329            }
 7330        }
 7331    }
 7332
 7333    pub fn accept_edit_prediction(
 7334        &mut self,
 7335        _: &AcceptEditPrediction,
 7336        window: &mut Window,
 7337        cx: &mut Context<Self>,
 7338    ) {
 7339        if self.show_edit_predictions_in_menu() {
 7340            self.hide_context_menu(window, cx);
 7341        }
 7342
 7343        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7344            return;
 7345        };
 7346
 7347        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7348
 7349        match &active_edit_prediction.completion {
 7350            EditPrediction::Move { target, .. } => {
 7351                let target = *target;
 7352
 7353                if let Some(position_map) = &self.last_position_map {
 7354                    if position_map
 7355                        .visible_row_range
 7356                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7357                        || !self.edit_prediction_requires_modifier()
 7358                    {
 7359                        self.unfold_ranges(&[target..target], true, false, cx);
 7360                        // Note that this is also done in vim's handler of the Tab action.
 7361                        self.change_selections(
 7362                            SelectionEffects::scroll(Autoscroll::newest()),
 7363                            window,
 7364                            cx,
 7365                            |selections| {
 7366                                selections.select_anchor_ranges([target..target]);
 7367                            },
 7368                        );
 7369                        self.clear_row_highlights::<EditPredictionPreview>();
 7370
 7371                        self.edit_prediction_preview
 7372                            .set_previous_scroll_position(None);
 7373                    } else {
 7374                        self.edit_prediction_preview
 7375                            .set_previous_scroll_position(Some(
 7376                                position_map.snapshot.scroll_anchor,
 7377                            ));
 7378
 7379                        self.highlight_rows::<EditPredictionPreview>(
 7380                            target..target,
 7381                            cx.theme().colors().editor_highlighted_line_background,
 7382                            RowHighlightOptions {
 7383                                autoscroll: true,
 7384                                ..Default::default()
 7385                            },
 7386                            cx,
 7387                        );
 7388                        self.request_autoscroll(Autoscroll::fit(), cx);
 7389                    }
 7390                }
 7391            }
 7392            EditPrediction::Edit { edits, .. } => {
 7393                if let Some(provider) = self.edit_prediction_provider() {
 7394                    provider.accept(cx);
 7395                }
 7396
 7397                // Store the transaction ID and selections before applying the edit
 7398                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7399
 7400                let snapshot = self.buffer.read(cx).snapshot(cx);
 7401                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7402
 7403                self.buffer.update(cx, |buffer, cx| {
 7404                    buffer.edit(edits.iter().cloned(), None, cx)
 7405                });
 7406
 7407                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7408                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7409                });
 7410
 7411                let selections = self.selections.disjoint_anchors();
 7412                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7413                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7414                    if has_new_transaction {
 7415                        self.selection_history
 7416                            .insert_transaction(transaction_id_now, selections);
 7417                    }
 7418                }
 7419
 7420                self.update_visible_edit_prediction(window, cx);
 7421                if self.active_edit_prediction.is_none() {
 7422                    self.refresh_edit_prediction(true, true, window, cx);
 7423                }
 7424
 7425                cx.notify();
 7426            }
 7427        }
 7428
 7429        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7430    }
 7431
 7432    pub fn accept_partial_edit_prediction(
 7433        &mut self,
 7434        _: &AcceptPartialEditPrediction,
 7435        window: &mut Window,
 7436        cx: &mut Context<Self>,
 7437    ) {
 7438        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7439            return;
 7440        };
 7441        if self.selections.count() != 1 {
 7442            return;
 7443        }
 7444
 7445        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7446
 7447        match &active_edit_prediction.completion {
 7448            EditPrediction::Move { target, .. } => {
 7449                let target = *target;
 7450                self.change_selections(
 7451                    SelectionEffects::scroll(Autoscroll::newest()),
 7452                    window,
 7453                    cx,
 7454                    |selections| {
 7455                        selections.select_anchor_ranges([target..target]);
 7456                    },
 7457                );
 7458            }
 7459            EditPrediction::Edit { edits, .. } => {
 7460                // Find an insertion that starts at the cursor position.
 7461                let snapshot = self.buffer.read(cx).snapshot(cx);
 7462                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7463                let insertion = edits.iter().find_map(|(range, text)| {
 7464                    let range = range.to_offset(&snapshot);
 7465                    if range.is_empty() && range.start == cursor_offset {
 7466                        Some(text)
 7467                    } else {
 7468                        None
 7469                    }
 7470                });
 7471
 7472                if let Some(text) = insertion {
 7473                    let mut partial_completion = text
 7474                        .chars()
 7475                        .by_ref()
 7476                        .take_while(|c| c.is_alphabetic())
 7477                        .collect::<String>();
 7478                    if partial_completion.is_empty() {
 7479                        partial_completion = text
 7480                            .chars()
 7481                            .by_ref()
 7482                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7483                            .collect::<String>();
 7484                    }
 7485
 7486                    cx.emit(EditorEvent::InputHandled {
 7487                        utf16_range_to_replace: None,
 7488                        text: partial_completion.clone().into(),
 7489                    });
 7490
 7491                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7492
 7493                    self.refresh_edit_prediction(true, true, window, cx);
 7494                    cx.notify();
 7495                } else {
 7496                    self.accept_edit_prediction(&Default::default(), window, cx);
 7497                }
 7498            }
 7499        }
 7500    }
 7501
 7502    fn discard_edit_prediction(
 7503        &mut self,
 7504        should_report_edit_prediction_event: bool,
 7505        cx: &mut Context<Self>,
 7506    ) -> bool {
 7507        if should_report_edit_prediction_event {
 7508            let completion_id = self
 7509                .active_edit_prediction
 7510                .as_ref()
 7511                .and_then(|active_completion| active_completion.completion_id.clone());
 7512
 7513            self.report_edit_prediction_event(completion_id, false, cx);
 7514        }
 7515
 7516        if let Some(provider) = self.edit_prediction_provider() {
 7517            provider.discard(cx);
 7518        }
 7519
 7520        self.take_active_edit_prediction(cx)
 7521    }
 7522
 7523    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7524        let Some(provider) = self.edit_prediction_provider() else {
 7525            return;
 7526        };
 7527
 7528        let Some((_, buffer, _)) = self
 7529            .buffer
 7530            .read(cx)
 7531            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7532        else {
 7533            return;
 7534        };
 7535
 7536        let extension = buffer
 7537            .read(cx)
 7538            .file()
 7539            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7540
 7541        let event_type = match accepted {
 7542            true => "Edit Prediction Accepted",
 7543            false => "Edit Prediction Discarded",
 7544        };
 7545        telemetry::event!(
 7546            event_type,
 7547            provider = provider.name(),
 7548            prediction_id = id,
 7549            suggestion_accepted = accepted,
 7550            file_extension = extension,
 7551        );
 7552    }
 7553
 7554    pub fn has_active_edit_prediction(&self) -> bool {
 7555        self.active_edit_prediction.is_some()
 7556    }
 7557
 7558    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7559        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7560            return false;
 7561        };
 7562
 7563        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7564        self.clear_highlights::<EditPredictionHighlight>(cx);
 7565        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7566        true
 7567    }
 7568
 7569    /// Returns true when we're displaying the edit prediction popover below the cursor
 7570    /// like we are not previewing and the LSP autocomplete menu is visible
 7571    /// or we are in `when_holding_modifier` mode.
 7572    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7573        if self.edit_prediction_preview_is_active()
 7574            || !self.show_edit_predictions_in_menu()
 7575            || !self.edit_predictions_enabled()
 7576        {
 7577            return false;
 7578        }
 7579
 7580        if self.has_visible_completions_menu() {
 7581            return true;
 7582        }
 7583
 7584        has_completion && self.edit_prediction_requires_modifier()
 7585    }
 7586
 7587    fn handle_modifiers_changed(
 7588        &mut self,
 7589        modifiers: Modifiers,
 7590        position_map: &PositionMap,
 7591        window: &mut Window,
 7592        cx: &mut Context<Self>,
 7593    ) {
 7594        if self.show_edit_predictions_in_menu() {
 7595            self.update_edit_prediction_preview(&modifiers, window, cx);
 7596        }
 7597
 7598        self.update_selection_mode(&modifiers, position_map, window, cx);
 7599
 7600        let mouse_position = window.mouse_position();
 7601        if !position_map.text_hitbox.is_hovered(window) {
 7602            return;
 7603        }
 7604
 7605        self.update_hovered_link(
 7606            position_map.point_for_position(mouse_position),
 7607            &position_map.snapshot,
 7608            modifiers,
 7609            window,
 7610            cx,
 7611        )
 7612    }
 7613
 7614    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7615        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7616        if invert {
 7617            match multi_cursor_setting {
 7618                MultiCursorModifier::Alt => modifiers.alt,
 7619                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7620            }
 7621        } else {
 7622            match multi_cursor_setting {
 7623                MultiCursorModifier::Alt => modifiers.secondary(),
 7624                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7625            }
 7626        }
 7627    }
 7628
 7629    fn columnar_selection_mode(
 7630        modifiers: &Modifiers,
 7631        cx: &mut Context<Self>,
 7632    ) -> Option<ColumnarMode> {
 7633        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7634            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7635                Some(ColumnarMode::FromMouse)
 7636            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7637                Some(ColumnarMode::FromSelection)
 7638            } else {
 7639                None
 7640            }
 7641        } else {
 7642            None
 7643        }
 7644    }
 7645
 7646    fn update_selection_mode(
 7647        &mut self,
 7648        modifiers: &Modifiers,
 7649        position_map: &PositionMap,
 7650        window: &mut Window,
 7651        cx: &mut Context<Self>,
 7652    ) {
 7653        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7654            return;
 7655        };
 7656        if self.selections.pending.is_none() {
 7657            return;
 7658        }
 7659
 7660        let mouse_position = window.mouse_position();
 7661        let point_for_position = position_map.point_for_position(mouse_position);
 7662        let position = point_for_position.previous_valid;
 7663
 7664        self.select(
 7665            SelectPhase::BeginColumnar {
 7666                position,
 7667                reset: false,
 7668                mode,
 7669                goal_column: point_for_position.exact_unclipped.column(),
 7670            },
 7671            window,
 7672            cx,
 7673        );
 7674    }
 7675
 7676    fn update_edit_prediction_preview(
 7677        &mut self,
 7678        modifiers: &Modifiers,
 7679        window: &mut Window,
 7680        cx: &mut Context<Self>,
 7681    ) {
 7682        let mut modifiers_held = false;
 7683        if let Some(accept_keystroke) = self
 7684            .accept_edit_prediction_keybind(false, window, cx)
 7685            .keystroke()
 7686        {
 7687            modifiers_held = modifiers_held
 7688                || (accept_keystroke.modifiers() == modifiers
 7689                    && accept_keystroke.modifiers().modified());
 7690        };
 7691        if let Some(accept_partial_keystroke) = self
 7692            .accept_edit_prediction_keybind(true, window, cx)
 7693            .keystroke()
 7694        {
 7695            modifiers_held = modifiers_held
 7696                || (accept_partial_keystroke.modifiers() == modifiers
 7697                    && accept_partial_keystroke.modifiers().modified());
 7698        }
 7699
 7700        if modifiers_held {
 7701            if matches!(
 7702                self.edit_prediction_preview,
 7703                EditPredictionPreview::Inactive { .. }
 7704            ) {
 7705                self.edit_prediction_preview = EditPredictionPreview::Active {
 7706                    previous_scroll_position: None,
 7707                    since: Instant::now(),
 7708                };
 7709
 7710                self.update_visible_edit_prediction(window, cx);
 7711                cx.notify();
 7712            }
 7713        } else if let EditPredictionPreview::Active {
 7714            previous_scroll_position,
 7715            since,
 7716        } = self.edit_prediction_preview
 7717        {
 7718            if let (Some(previous_scroll_position), Some(position_map)) =
 7719                (previous_scroll_position, self.last_position_map.as_ref())
 7720            {
 7721                self.set_scroll_position(
 7722                    previous_scroll_position
 7723                        .scroll_position(&position_map.snapshot.display_snapshot),
 7724                    window,
 7725                    cx,
 7726                );
 7727            }
 7728
 7729            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7730                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7731            };
 7732            self.clear_row_highlights::<EditPredictionPreview>();
 7733            self.update_visible_edit_prediction(window, cx);
 7734            cx.notify();
 7735        }
 7736    }
 7737
 7738    fn update_visible_edit_prediction(
 7739        &mut self,
 7740        _window: &mut Window,
 7741        cx: &mut Context<Self>,
 7742    ) -> Option<()> {
 7743        if DisableAiSettings::get_global(cx).disable_ai {
 7744            return None;
 7745        }
 7746
 7747        let selection = self.selections.newest_anchor();
 7748        let cursor = selection.head();
 7749        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7750        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7751        let excerpt_id = cursor.excerpt_id;
 7752
 7753        let show_in_menu = self.show_edit_predictions_in_menu();
 7754        let completions_menu_has_precedence = !show_in_menu
 7755            && (self.context_menu.borrow().is_some()
 7756                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7757
 7758        if completions_menu_has_precedence
 7759            || !offset_selection.is_empty()
 7760            || self
 7761                .active_edit_prediction
 7762                .as_ref()
 7763                .is_some_and(|completion| {
 7764                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7765                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7766                    !invalidation_range.contains(&offset_selection.head())
 7767                })
 7768        {
 7769            self.discard_edit_prediction(false, cx);
 7770            return None;
 7771        }
 7772
 7773        self.take_active_edit_prediction(cx);
 7774        let Some(provider) = self.edit_prediction_provider() else {
 7775            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7776            return None;
 7777        };
 7778
 7779        let (buffer, cursor_buffer_position) =
 7780            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7781
 7782        self.edit_prediction_settings =
 7783            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7784
 7785        if let EditPredictionSettings::Disabled = self.edit_prediction_settings {
 7786            self.discard_edit_prediction(false, cx);
 7787            return None;
 7788        };
 7789
 7790        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7791
 7792        if self.edit_prediction_indent_conflict {
 7793            let cursor_point = cursor.to_point(&multibuffer);
 7794
 7795            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7796
 7797            if let Some((_, indent)) = indents.iter().next()
 7798                && indent.len == cursor_point.column
 7799            {
 7800                self.edit_prediction_indent_conflict = false;
 7801            }
 7802        }
 7803
 7804        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7805        let edits = edit_prediction
 7806            .edits
 7807            .into_iter()
 7808            .flat_map(|(range, new_text)| {
 7809                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7810                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7811                Some((start..end, new_text))
 7812            })
 7813            .collect::<Vec<_>>();
 7814        if edits.is_empty() {
 7815            return None;
 7816        }
 7817
 7818        let first_edit_start = edits.first().unwrap().0.start;
 7819        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7820        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7821
 7822        let last_edit_end = edits.last().unwrap().0.end;
 7823        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7824        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7825
 7826        let cursor_row = cursor.to_point(&multibuffer).row;
 7827
 7828        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7829
 7830        let mut inlay_ids = Vec::new();
 7831        let invalidation_row_range;
 7832        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7833            Some(cursor_row..edit_end_row)
 7834        } else if cursor_row > edit_end_row {
 7835            Some(edit_start_row..cursor_row)
 7836        } else {
 7837            None
 7838        };
 7839        let supports_jump = self
 7840            .edit_prediction_provider
 7841            .as_ref()
 7842            .map(|provider| provider.provider.supports_jump_to_edit())
 7843            .unwrap_or(true);
 7844
 7845        let is_move = supports_jump
 7846            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7847        let completion = if is_move {
 7848            invalidation_row_range =
 7849                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7850            let target = first_edit_start;
 7851            EditPrediction::Move { target, snapshot }
 7852        } else {
 7853            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7854                && !self.edit_predictions_hidden_for_vim_mode;
 7855
 7856            if show_completions_in_buffer {
 7857                if edits
 7858                    .iter()
 7859                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7860                {
 7861                    let mut inlays = Vec::new();
 7862                    for (range, new_text) in &edits {
 7863                        let inlay = Inlay::edit_prediction(
 7864                            post_inc(&mut self.next_inlay_id),
 7865                            range.start,
 7866                            new_text.as_str(),
 7867                        );
 7868                        inlay_ids.push(inlay.id);
 7869                        inlays.push(inlay);
 7870                    }
 7871
 7872                    self.splice_inlays(&[], inlays, cx);
 7873                } else {
 7874                    let background_color = cx.theme().status().deleted_background;
 7875                    self.highlight_text::<EditPredictionHighlight>(
 7876                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7877                        HighlightStyle {
 7878                            background_color: Some(background_color),
 7879                            ..Default::default()
 7880                        },
 7881                        cx,
 7882                    );
 7883                }
 7884            }
 7885
 7886            invalidation_row_range = edit_start_row..edit_end_row;
 7887
 7888            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7889                if provider.show_tab_accept_marker() {
 7890                    EditDisplayMode::TabAccept
 7891                } else {
 7892                    EditDisplayMode::Inline
 7893                }
 7894            } else {
 7895                EditDisplayMode::DiffPopover
 7896            };
 7897
 7898            EditPrediction::Edit {
 7899                edits,
 7900                edit_preview: edit_prediction.edit_preview,
 7901                display_mode,
 7902                snapshot,
 7903            }
 7904        };
 7905
 7906        let invalidation_range = multibuffer
 7907            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7908            ..multibuffer.anchor_after(Point::new(
 7909                invalidation_row_range.end,
 7910                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7911            ));
 7912
 7913        self.stale_edit_prediction_in_menu = None;
 7914        self.active_edit_prediction = Some(EditPredictionState {
 7915            inlay_ids,
 7916            completion,
 7917            completion_id: edit_prediction.id,
 7918            invalidation_range,
 7919        });
 7920
 7921        cx.notify();
 7922
 7923        Some(())
 7924    }
 7925
 7926    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7927        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7928    }
 7929
 7930    fn clear_tasks(&mut self) {
 7931        self.tasks.clear()
 7932    }
 7933
 7934    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7935        if self.tasks.insert(key, value).is_some() {
 7936            // This case should hopefully be rare, but just in case...
 7937            log::error!(
 7938                "multiple different run targets found on a single line, only the last target will be rendered"
 7939            )
 7940        }
 7941    }
 7942
 7943    /// Get all display points of breakpoints that will be rendered within editor
 7944    ///
 7945    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7946    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7947    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7948    fn active_breakpoints(
 7949        &self,
 7950        range: Range<DisplayRow>,
 7951        window: &mut Window,
 7952        cx: &mut Context<Self>,
 7953    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7954        let mut breakpoint_display_points = HashMap::default();
 7955
 7956        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7957            return breakpoint_display_points;
 7958        };
 7959
 7960        let snapshot = self.snapshot(window, cx);
 7961
 7962        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7963        let Some(project) = self.project() else {
 7964            return breakpoint_display_points;
 7965        };
 7966
 7967        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7968            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7969
 7970        for (buffer_snapshot, range, excerpt_id) in
 7971            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7972        {
 7973            let Some(buffer) = project
 7974                .read(cx)
 7975                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7976            else {
 7977                continue;
 7978            };
 7979            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7980                &buffer,
 7981                Some(
 7982                    buffer_snapshot.anchor_before(range.start)
 7983                        ..buffer_snapshot.anchor_after(range.end),
 7984                ),
 7985                buffer_snapshot,
 7986                cx,
 7987            );
 7988            for (breakpoint, state) in breakpoints {
 7989                let multi_buffer_anchor =
 7990                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7991                let position = multi_buffer_anchor
 7992                    .to_point(multi_buffer_snapshot)
 7993                    .to_display_point(&snapshot);
 7994
 7995                breakpoint_display_points.insert(
 7996                    position.row(),
 7997                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7998                );
 7999            }
 8000        }
 8001
 8002        breakpoint_display_points
 8003    }
 8004
 8005    fn breakpoint_context_menu(
 8006        &self,
 8007        anchor: Anchor,
 8008        window: &mut Window,
 8009        cx: &mut Context<Self>,
 8010    ) -> Entity<ui::ContextMenu> {
 8011        let weak_editor = cx.weak_entity();
 8012        let focus_handle = self.focus_handle(cx);
 8013
 8014        let row = self
 8015            .buffer
 8016            .read(cx)
 8017            .snapshot(cx)
 8018            .summary_for_anchor::<Point>(&anchor)
 8019            .row;
 8020
 8021        let breakpoint = self
 8022            .breakpoint_at_row(row, window, cx)
 8023            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8024
 8025        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8026            "Edit Log Breakpoint"
 8027        } else {
 8028            "Set Log Breakpoint"
 8029        };
 8030
 8031        let condition_breakpoint_msg = if breakpoint
 8032            .as_ref()
 8033            .is_some_and(|bp| bp.1.condition.is_some())
 8034        {
 8035            "Edit Condition Breakpoint"
 8036        } else {
 8037            "Set Condition Breakpoint"
 8038        };
 8039
 8040        let hit_condition_breakpoint_msg = if breakpoint
 8041            .as_ref()
 8042            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8043        {
 8044            "Edit Hit Condition Breakpoint"
 8045        } else {
 8046            "Set Hit Condition Breakpoint"
 8047        };
 8048
 8049        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8050            "Unset Breakpoint"
 8051        } else {
 8052            "Set Breakpoint"
 8053        };
 8054
 8055        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8056
 8057        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8058            BreakpointState::Enabled => Some("Disable"),
 8059            BreakpointState::Disabled => Some("Enable"),
 8060        });
 8061
 8062        let (anchor, breakpoint) =
 8063            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8064
 8065        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8066            menu.on_blur_subscription(Subscription::new(|| {}))
 8067                .context(focus_handle)
 8068                .when(run_to_cursor, |this| {
 8069                    let weak_editor = weak_editor.clone();
 8070                    this.entry("Run to cursor", None, move |window, cx| {
 8071                        weak_editor
 8072                            .update(cx, |editor, cx| {
 8073                                editor.change_selections(
 8074                                    SelectionEffects::no_scroll(),
 8075                                    window,
 8076                                    cx,
 8077                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8078                                );
 8079                            })
 8080                            .ok();
 8081
 8082                        window.dispatch_action(Box::new(RunToCursor), cx);
 8083                    })
 8084                    .separator()
 8085                })
 8086                .when_some(toggle_state_msg, |this, msg| {
 8087                    this.entry(msg, None, {
 8088                        let weak_editor = weak_editor.clone();
 8089                        let breakpoint = breakpoint.clone();
 8090                        move |_window, cx| {
 8091                            weak_editor
 8092                                .update(cx, |this, cx| {
 8093                                    this.edit_breakpoint_at_anchor(
 8094                                        anchor,
 8095                                        breakpoint.as_ref().clone(),
 8096                                        BreakpointEditAction::InvertState,
 8097                                        cx,
 8098                                    );
 8099                                })
 8100                                .log_err();
 8101                        }
 8102                    })
 8103                })
 8104                .entry(set_breakpoint_msg, None, {
 8105                    let weak_editor = weak_editor.clone();
 8106                    let breakpoint = breakpoint.clone();
 8107                    move |_window, cx| {
 8108                        weak_editor
 8109                            .update(cx, |this, cx| {
 8110                                this.edit_breakpoint_at_anchor(
 8111                                    anchor,
 8112                                    breakpoint.as_ref().clone(),
 8113                                    BreakpointEditAction::Toggle,
 8114                                    cx,
 8115                                );
 8116                            })
 8117                            .log_err();
 8118                    }
 8119                })
 8120                .entry(log_breakpoint_msg, None, {
 8121                    let breakpoint = breakpoint.clone();
 8122                    let weak_editor = weak_editor.clone();
 8123                    move |window, cx| {
 8124                        weak_editor
 8125                            .update(cx, |this, cx| {
 8126                                this.add_edit_breakpoint_block(
 8127                                    anchor,
 8128                                    breakpoint.as_ref(),
 8129                                    BreakpointPromptEditAction::Log,
 8130                                    window,
 8131                                    cx,
 8132                                );
 8133                            })
 8134                            .log_err();
 8135                    }
 8136                })
 8137                .entry(condition_breakpoint_msg, None, {
 8138                    let breakpoint = breakpoint.clone();
 8139                    let weak_editor = weak_editor.clone();
 8140                    move |window, cx| {
 8141                        weak_editor
 8142                            .update(cx, |this, cx| {
 8143                                this.add_edit_breakpoint_block(
 8144                                    anchor,
 8145                                    breakpoint.as_ref(),
 8146                                    BreakpointPromptEditAction::Condition,
 8147                                    window,
 8148                                    cx,
 8149                                );
 8150                            })
 8151                            .log_err();
 8152                    }
 8153                })
 8154                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8155                    weak_editor
 8156                        .update(cx, |this, cx| {
 8157                            this.add_edit_breakpoint_block(
 8158                                anchor,
 8159                                breakpoint.as_ref(),
 8160                                BreakpointPromptEditAction::HitCondition,
 8161                                window,
 8162                                cx,
 8163                            );
 8164                        })
 8165                        .log_err();
 8166                })
 8167        })
 8168    }
 8169
 8170    fn render_breakpoint(
 8171        &self,
 8172        position: Anchor,
 8173        row: DisplayRow,
 8174        breakpoint: &Breakpoint,
 8175        state: Option<BreakpointSessionState>,
 8176        cx: &mut Context<Self>,
 8177    ) -> IconButton {
 8178        let is_rejected = state.is_some_and(|s| !s.verified);
 8179        // Is it a breakpoint that shows up when hovering over gutter?
 8180        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8181            (false, false),
 8182            |PhantomBreakpointIndicator {
 8183                 is_active,
 8184                 display_row,
 8185                 collides_with_existing_breakpoint,
 8186             }| {
 8187                (
 8188                    is_active && display_row == row,
 8189                    collides_with_existing_breakpoint,
 8190                )
 8191            },
 8192        );
 8193
 8194        let (color, icon) = {
 8195            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8196                (false, false) => ui::IconName::DebugBreakpoint,
 8197                (true, false) => ui::IconName::DebugLogBreakpoint,
 8198                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8199                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8200            };
 8201
 8202            let color = if is_phantom {
 8203                Color::Hint
 8204            } else if is_rejected {
 8205                Color::Disabled
 8206            } else {
 8207                Color::Debugger
 8208            };
 8209
 8210            (color, icon)
 8211        };
 8212
 8213        let breakpoint = Arc::from(breakpoint.clone());
 8214
 8215        let alt_as_text = gpui::Keystroke {
 8216            modifiers: Modifiers::secondary_key(),
 8217            ..Default::default()
 8218        };
 8219        let primary_action_text = if breakpoint.is_disabled() {
 8220            "Enable breakpoint"
 8221        } else if is_phantom && !collides_with_existing {
 8222            "Set breakpoint"
 8223        } else {
 8224            "Unset breakpoint"
 8225        };
 8226        let focus_handle = self.focus_handle.clone();
 8227
 8228        let meta = if is_rejected {
 8229            SharedString::from("No executable code is associated with this line.")
 8230        } else if collides_with_existing && !breakpoint.is_disabled() {
 8231            SharedString::from(format!(
 8232                "{alt_as_text}-click to disable,\nright-click for more options."
 8233            ))
 8234        } else {
 8235            SharedString::from("Right-click for more options.")
 8236        };
 8237        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8238            .icon_size(IconSize::XSmall)
 8239            .size(ui::ButtonSize::None)
 8240            .when(is_rejected, |this| {
 8241                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8242            })
 8243            .icon_color(color)
 8244            .style(ButtonStyle::Transparent)
 8245            .on_click(cx.listener({
 8246                move |editor, event: &ClickEvent, window, cx| {
 8247                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8248                        BreakpointEditAction::InvertState
 8249                    } else {
 8250                        BreakpointEditAction::Toggle
 8251                    };
 8252
 8253                    window.focus(&editor.focus_handle(cx));
 8254                    editor.edit_breakpoint_at_anchor(
 8255                        position,
 8256                        breakpoint.as_ref().clone(),
 8257                        edit_action,
 8258                        cx,
 8259                    );
 8260                }
 8261            }))
 8262            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8263                editor.set_breakpoint_context_menu(
 8264                    row,
 8265                    Some(position),
 8266                    event.position(),
 8267                    window,
 8268                    cx,
 8269                );
 8270            }))
 8271            .tooltip(move |window, cx| {
 8272                Tooltip::with_meta_in(
 8273                    primary_action_text,
 8274                    Some(&ToggleBreakpoint),
 8275                    meta.clone(),
 8276                    &focus_handle,
 8277                    window,
 8278                    cx,
 8279                )
 8280            })
 8281    }
 8282
 8283    fn build_tasks_context(
 8284        project: &Entity<Project>,
 8285        buffer: &Entity<Buffer>,
 8286        buffer_row: u32,
 8287        tasks: &Arc<RunnableTasks>,
 8288        cx: &mut Context<Self>,
 8289    ) -> Task<Option<task::TaskContext>> {
 8290        let position = Point::new(buffer_row, tasks.column);
 8291        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8292        let location = Location {
 8293            buffer: buffer.clone(),
 8294            range: range_start..range_start,
 8295        };
 8296        // Fill in the environmental variables from the tree-sitter captures
 8297        let mut captured_task_variables = TaskVariables::default();
 8298        for (capture_name, value) in tasks.extra_variables.clone() {
 8299            captured_task_variables.insert(
 8300                task::VariableName::Custom(capture_name.into()),
 8301                value.clone(),
 8302            );
 8303        }
 8304        project.update(cx, |project, cx| {
 8305            project.task_store().update(cx, |task_store, cx| {
 8306                task_store.task_context_for_location(captured_task_variables, location, cx)
 8307            })
 8308        })
 8309    }
 8310
 8311    pub fn spawn_nearest_task(
 8312        &mut self,
 8313        action: &SpawnNearestTask,
 8314        window: &mut Window,
 8315        cx: &mut Context<Self>,
 8316    ) {
 8317        let Some((workspace, _)) = self.workspace.clone() else {
 8318            return;
 8319        };
 8320        let Some(project) = self.project.clone() else {
 8321            return;
 8322        };
 8323
 8324        // Try to find a closest, enclosing node using tree-sitter that has a task
 8325        let Some((buffer, buffer_row, tasks)) = self
 8326            .find_enclosing_node_task(cx)
 8327            // Or find the task that's closest in row-distance.
 8328            .or_else(|| self.find_closest_task(cx))
 8329        else {
 8330            return;
 8331        };
 8332
 8333        let reveal_strategy = action.reveal;
 8334        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8335        cx.spawn_in(window, async move |_, cx| {
 8336            let context = task_context.await?;
 8337            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8338
 8339            let resolved = &mut resolved_task.resolved;
 8340            resolved.reveal = reveal_strategy;
 8341
 8342            workspace
 8343                .update_in(cx, |workspace, window, cx| {
 8344                    workspace.schedule_resolved_task(
 8345                        task_source_kind,
 8346                        resolved_task,
 8347                        false,
 8348                        window,
 8349                        cx,
 8350                    );
 8351                })
 8352                .ok()
 8353        })
 8354        .detach();
 8355    }
 8356
 8357    fn find_closest_task(
 8358        &mut self,
 8359        cx: &mut Context<Self>,
 8360    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8361        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8362
 8363        let ((buffer_id, row), tasks) = self
 8364            .tasks
 8365            .iter()
 8366            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8367
 8368        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8369        let tasks = Arc::new(tasks.to_owned());
 8370        Some((buffer, *row, tasks))
 8371    }
 8372
 8373    fn find_enclosing_node_task(
 8374        &mut self,
 8375        cx: &mut Context<Self>,
 8376    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8377        let snapshot = self.buffer.read(cx).snapshot(cx);
 8378        let offset = self.selections.newest::<usize>(cx).head();
 8379        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8380        let buffer_id = excerpt.buffer().remote_id();
 8381
 8382        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8383        let mut cursor = layer.node().walk();
 8384
 8385        while cursor.goto_first_child_for_byte(offset).is_some() {
 8386            if cursor.node().end_byte() == offset {
 8387                cursor.goto_next_sibling();
 8388            }
 8389        }
 8390
 8391        // Ascend to the smallest ancestor that contains the range and has a task.
 8392        loop {
 8393            let node = cursor.node();
 8394            let node_range = node.byte_range();
 8395            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8396
 8397            // Check if this node contains our offset
 8398            if node_range.start <= offset && node_range.end >= offset {
 8399                // If it contains offset, check for task
 8400                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8401                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8402                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8403                }
 8404            }
 8405
 8406            if !cursor.goto_parent() {
 8407                break;
 8408            }
 8409        }
 8410        None
 8411    }
 8412
 8413    fn render_run_indicator(
 8414        &self,
 8415        _style: &EditorStyle,
 8416        is_active: bool,
 8417        row: DisplayRow,
 8418        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8419        cx: &mut Context<Self>,
 8420    ) -> IconButton {
 8421        let color = Color::Muted;
 8422        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8423
 8424        IconButton::new(
 8425            ("run_indicator", row.0 as usize),
 8426            ui::IconName::PlayOutlined,
 8427        )
 8428        .shape(ui::IconButtonShape::Square)
 8429        .icon_size(IconSize::XSmall)
 8430        .icon_color(color)
 8431        .toggle_state(is_active)
 8432        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8433            let quick_launch = match e {
 8434                ClickEvent::Keyboard(_) => true,
 8435                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8436            };
 8437
 8438            window.focus(&editor.focus_handle(cx));
 8439            editor.toggle_code_actions(
 8440                &ToggleCodeActions {
 8441                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8442                    quick_launch,
 8443                },
 8444                window,
 8445                cx,
 8446            );
 8447        }))
 8448        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8449            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8450        }))
 8451    }
 8452
 8453    pub fn context_menu_visible(&self) -> bool {
 8454        !self.edit_prediction_preview_is_active()
 8455            && self
 8456                .context_menu
 8457                .borrow()
 8458                .as_ref()
 8459                .is_some_and(|menu| menu.visible())
 8460    }
 8461
 8462    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8463        self.context_menu
 8464            .borrow()
 8465            .as_ref()
 8466            .map(|menu| menu.origin())
 8467    }
 8468
 8469    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8470        self.context_menu_options = Some(options);
 8471    }
 8472
 8473    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8474    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8475
 8476    fn render_edit_prediction_popover(
 8477        &mut self,
 8478        text_bounds: &Bounds<Pixels>,
 8479        content_origin: gpui::Point<Pixels>,
 8480        right_margin: Pixels,
 8481        editor_snapshot: &EditorSnapshot,
 8482        visible_row_range: Range<DisplayRow>,
 8483        scroll_top: f32,
 8484        scroll_bottom: f32,
 8485        line_layouts: &[LineWithInvisibles],
 8486        line_height: Pixels,
 8487        scroll_pixel_position: gpui::Point<Pixels>,
 8488        newest_selection_head: Option<DisplayPoint>,
 8489        editor_width: Pixels,
 8490        style: &EditorStyle,
 8491        window: &mut Window,
 8492        cx: &mut App,
 8493    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8494        if self.mode().is_minimap() {
 8495            return None;
 8496        }
 8497        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8498
 8499        if self.edit_prediction_visible_in_cursor_popover(true) {
 8500            return None;
 8501        }
 8502
 8503        match &active_edit_prediction.completion {
 8504            EditPrediction::Move { target, .. } => {
 8505                let target_display_point = target.to_display_point(editor_snapshot);
 8506
 8507                if self.edit_prediction_requires_modifier() {
 8508                    if !self.edit_prediction_preview_is_active() {
 8509                        return None;
 8510                    }
 8511
 8512                    self.render_edit_prediction_modifier_jump_popover(
 8513                        text_bounds,
 8514                        content_origin,
 8515                        visible_row_range,
 8516                        line_layouts,
 8517                        line_height,
 8518                        scroll_pixel_position,
 8519                        newest_selection_head,
 8520                        target_display_point,
 8521                        window,
 8522                        cx,
 8523                    )
 8524                } else {
 8525                    self.render_edit_prediction_eager_jump_popover(
 8526                        text_bounds,
 8527                        content_origin,
 8528                        editor_snapshot,
 8529                        visible_row_range,
 8530                        scroll_top,
 8531                        scroll_bottom,
 8532                        line_height,
 8533                        scroll_pixel_position,
 8534                        target_display_point,
 8535                        editor_width,
 8536                        window,
 8537                        cx,
 8538                    )
 8539                }
 8540            }
 8541            EditPrediction::Edit {
 8542                display_mode: EditDisplayMode::Inline,
 8543                ..
 8544            } => None,
 8545            EditPrediction::Edit {
 8546                display_mode: EditDisplayMode::TabAccept,
 8547                edits,
 8548                ..
 8549            } => {
 8550                let range = &edits.first()?.0;
 8551                let target_display_point = range.end.to_display_point(editor_snapshot);
 8552
 8553                self.render_edit_prediction_end_of_line_popover(
 8554                    "Accept",
 8555                    editor_snapshot,
 8556                    visible_row_range,
 8557                    target_display_point,
 8558                    line_height,
 8559                    scroll_pixel_position,
 8560                    content_origin,
 8561                    editor_width,
 8562                    window,
 8563                    cx,
 8564                )
 8565            }
 8566            EditPrediction::Edit {
 8567                edits,
 8568                edit_preview,
 8569                display_mode: EditDisplayMode::DiffPopover,
 8570                snapshot,
 8571            } => self.render_edit_prediction_diff_popover(
 8572                text_bounds,
 8573                content_origin,
 8574                right_margin,
 8575                editor_snapshot,
 8576                visible_row_range,
 8577                line_layouts,
 8578                line_height,
 8579                scroll_pixel_position,
 8580                newest_selection_head,
 8581                editor_width,
 8582                style,
 8583                edits,
 8584                edit_preview,
 8585                snapshot,
 8586                window,
 8587                cx,
 8588            ),
 8589        }
 8590    }
 8591
 8592    fn render_edit_prediction_modifier_jump_popover(
 8593        &mut self,
 8594        text_bounds: &Bounds<Pixels>,
 8595        content_origin: gpui::Point<Pixels>,
 8596        visible_row_range: Range<DisplayRow>,
 8597        line_layouts: &[LineWithInvisibles],
 8598        line_height: Pixels,
 8599        scroll_pixel_position: gpui::Point<Pixels>,
 8600        newest_selection_head: Option<DisplayPoint>,
 8601        target_display_point: DisplayPoint,
 8602        window: &mut Window,
 8603        cx: &mut App,
 8604    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8605        let scrolled_content_origin =
 8606            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8607
 8608        const SCROLL_PADDING_Y: Pixels = px(12.);
 8609
 8610        if target_display_point.row() < visible_row_range.start {
 8611            return self.render_edit_prediction_scroll_popover(
 8612                |_| SCROLL_PADDING_Y,
 8613                IconName::ArrowUp,
 8614                visible_row_range,
 8615                line_layouts,
 8616                newest_selection_head,
 8617                scrolled_content_origin,
 8618                window,
 8619                cx,
 8620            );
 8621        } else if target_display_point.row() >= visible_row_range.end {
 8622            return self.render_edit_prediction_scroll_popover(
 8623                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8624                IconName::ArrowDown,
 8625                visible_row_range,
 8626                line_layouts,
 8627                newest_selection_head,
 8628                scrolled_content_origin,
 8629                window,
 8630                cx,
 8631            );
 8632        }
 8633
 8634        const POLE_WIDTH: Pixels = px(2.);
 8635
 8636        let line_layout =
 8637            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8638        let target_column = target_display_point.column() as usize;
 8639
 8640        let target_x = line_layout.x_for_index(target_column);
 8641        let target_y =
 8642            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8643
 8644        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8645
 8646        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8647        border_color.l += 0.001;
 8648
 8649        let mut element = v_flex()
 8650            .items_end()
 8651            .when(flag_on_right, |el| el.items_start())
 8652            .child(if flag_on_right {
 8653                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8654                    .rounded_bl(px(0.))
 8655                    .rounded_tl(px(0.))
 8656                    .border_l_2()
 8657                    .border_color(border_color)
 8658            } else {
 8659                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8660                    .rounded_br(px(0.))
 8661                    .rounded_tr(px(0.))
 8662                    .border_r_2()
 8663                    .border_color(border_color)
 8664            })
 8665            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8666            .into_any();
 8667
 8668        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8669
 8670        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8671            - point(
 8672                if flag_on_right {
 8673                    POLE_WIDTH
 8674                } else {
 8675                    size.width - POLE_WIDTH
 8676                },
 8677                size.height - line_height,
 8678            );
 8679
 8680        origin.x = origin.x.max(content_origin.x);
 8681
 8682        element.prepaint_at(origin, window, cx);
 8683
 8684        Some((element, origin))
 8685    }
 8686
 8687    fn render_edit_prediction_scroll_popover(
 8688        &mut self,
 8689        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8690        scroll_icon: IconName,
 8691        visible_row_range: Range<DisplayRow>,
 8692        line_layouts: &[LineWithInvisibles],
 8693        newest_selection_head: Option<DisplayPoint>,
 8694        scrolled_content_origin: gpui::Point<Pixels>,
 8695        window: &mut Window,
 8696        cx: &mut App,
 8697    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8698        let mut element = self
 8699            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8700            .into_any();
 8701
 8702        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8703
 8704        let cursor = newest_selection_head?;
 8705        let cursor_row_layout =
 8706            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8707        let cursor_column = cursor.column() as usize;
 8708
 8709        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8710
 8711        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8712
 8713        element.prepaint_at(origin, window, cx);
 8714        Some((element, origin))
 8715    }
 8716
 8717    fn render_edit_prediction_eager_jump_popover(
 8718        &mut self,
 8719        text_bounds: &Bounds<Pixels>,
 8720        content_origin: gpui::Point<Pixels>,
 8721        editor_snapshot: &EditorSnapshot,
 8722        visible_row_range: Range<DisplayRow>,
 8723        scroll_top: f32,
 8724        scroll_bottom: f32,
 8725        line_height: Pixels,
 8726        scroll_pixel_position: gpui::Point<Pixels>,
 8727        target_display_point: DisplayPoint,
 8728        editor_width: Pixels,
 8729        window: &mut Window,
 8730        cx: &mut App,
 8731    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8732        if target_display_point.row().as_f32() < scroll_top {
 8733            let mut element = self
 8734                .render_edit_prediction_line_popover(
 8735                    "Jump to Edit",
 8736                    Some(IconName::ArrowUp),
 8737                    window,
 8738                    cx,
 8739                )?
 8740                .into_any();
 8741
 8742            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8743            let offset = point(
 8744                (text_bounds.size.width - size.width) / 2.,
 8745                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8746            );
 8747
 8748            let origin = text_bounds.origin + offset;
 8749            element.prepaint_at(origin, window, cx);
 8750            Some((element, origin))
 8751        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8752            let mut element = self
 8753                .render_edit_prediction_line_popover(
 8754                    "Jump to Edit",
 8755                    Some(IconName::ArrowDown),
 8756                    window,
 8757                    cx,
 8758                )?
 8759                .into_any();
 8760
 8761            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8762            let offset = point(
 8763                (text_bounds.size.width - size.width) / 2.,
 8764                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8765            );
 8766
 8767            let origin = text_bounds.origin + offset;
 8768            element.prepaint_at(origin, window, cx);
 8769            Some((element, origin))
 8770        } else {
 8771            self.render_edit_prediction_end_of_line_popover(
 8772                "Jump to Edit",
 8773                editor_snapshot,
 8774                visible_row_range,
 8775                target_display_point,
 8776                line_height,
 8777                scroll_pixel_position,
 8778                content_origin,
 8779                editor_width,
 8780                window,
 8781                cx,
 8782            )
 8783        }
 8784    }
 8785
 8786    fn render_edit_prediction_end_of_line_popover(
 8787        self: &mut Editor,
 8788        label: &'static str,
 8789        editor_snapshot: &EditorSnapshot,
 8790        visible_row_range: Range<DisplayRow>,
 8791        target_display_point: DisplayPoint,
 8792        line_height: Pixels,
 8793        scroll_pixel_position: gpui::Point<Pixels>,
 8794        content_origin: gpui::Point<Pixels>,
 8795        editor_width: Pixels,
 8796        window: &mut Window,
 8797        cx: &mut App,
 8798    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8799        let target_line_end = DisplayPoint::new(
 8800            target_display_point.row(),
 8801            editor_snapshot.line_len(target_display_point.row()),
 8802        );
 8803
 8804        let mut element = self
 8805            .render_edit_prediction_line_popover(label, None, window, cx)?
 8806            .into_any();
 8807
 8808        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8809
 8810        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8811
 8812        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8813        let mut origin = start_point
 8814            + line_origin
 8815            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8816        origin.x = origin.x.max(content_origin.x);
 8817
 8818        let max_x = content_origin.x + editor_width - size.width;
 8819
 8820        if origin.x > max_x {
 8821            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8822
 8823            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8824                origin.y += offset;
 8825                IconName::ArrowUp
 8826            } else {
 8827                origin.y -= offset;
 8828                IconName::ArrowDown
 8829            };
 8830
 8831            element = self
 8832                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8833                .into_any();
 8834
 8835            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8836
 8837            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8838        }
 8839
 8840        element.prepaint_at(origin, window, cx);
 8841        Some((element, origin))
 8842    }
 8843
 8844    fn render_edit_prediction_diff_popover(
 8845        self: &Editor,
 8846        text_bounds: &Bounds<Pixels>,
 8847        content_origin: gpui::Point<Pixels>,
 8848        right_margin: Pixels,
 8849        editor_snapshot: &EditorSnapshot,
 8850        visible_row_range: Range<DisplayRow>,
 8851        line_layouts: &[LineWithInvisibles],
 8852        line_height: Pixels,
 8853        scroll_pixel_position: gpui::Point<Pixels>,
 8854        newest_selection_head: Option<DisplayPoint>,
 8855        editor_width: Pixels,
 8856        style: &EditorStyle,
 8857        edits: &Vec<(Range<Anchor>, String)>,
 8858        edit_preview: &Option<language::EditPreview>,
 8859        snapshot: &language::BufferSnapshot,
 8860        window: &mut Window,
 8861        cx: &mut App,
 8862    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8863        let edit_start = edits
 8864            .first()
 8865            .unwrap()
 8866            .0
 8867            .start
 8868            .to_display_point(editor_snapshot);
 8869        let edit_end = edits
 8870            .last()
 8871            .unwrap()
 8872            .0
 8873            .end
 8874            .to_display_point(editor_snapshot);
 8875
 8876        let is_visible = visible_row_range.contains(&edit_start.row())
 8877            || visible_row_range.contains(&edit_end.row());
 8878        if !is_visible {
 8879            return None;
 8880        }
 8881
 8882        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8883            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8884        } else {
 8885            // Fallback for providers without edit_preview
 8886            crate::edit_prediction_fallback_text(edits, cx)
 8887        };
 8888
 8889        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8890        let line_count = highlighted_edits.text.lines().count();
 8891
 8892        const BORDER_WIDTH: Pixels = px(1.);
 8893
 8894        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8895        let has_keybind = keybind.is_some();
 8896
 8897        let mut element = h_flex()
 8898            .items_start()
 8899            .child(
 8900                h_flex()
 8901                    .bg(cx.theme().colors().editor_background)
 8902                    .border(BORDER_WIDTH)
 8903                    .shadow_xs()
 8904                    .border_color(cx.theme().colors().border)
 8905                    .rounded_l_lg()
 8906                    .when(line_count > 1, |el| el.rounded_br_lg())
 8907                    .pr_1()
 8908                    .child(styled_text),
 8909            )
 8910            .child(
 8911                h_flex()
 8912                    .h(line_height + BORDER_WIDTH * 2.)
 8913                    .px_1p5()
 8914                    .gap_1()
 8915                    // Workaround: For some reason, there's a gap if we don't do this
 8916                    .ml(-BORDER_WIDTH)
 8917                    .shadow(vec![gpui::BoxShadow {
 8918                        color: gpui::black().opacity(0.05),
 8919                        offset: point(px(1.), px(1.)),
 8920                        blur_radius: px(2.),
 8921                        spread_radius: px(0.),
 8922                    }])
 8923                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8924                    .border(BORDER_WIDTH)
 8925                    .border_color(cx.theme().colors().border)
 8926                    .rounded_r_lg()
 8927                    .id("edit_prediction_diff_popover_keybind")
 8928                    .when(!has_keybind, |el| {
 8929                        let status_colors = cx.theme().status();
 8930
 8931                        el.bg(status_colors.error_background)
 8932                            .border_color(status_colors.error.opacity(0.6))
 8933                            .child(Icon::new(IconName::Info).color(Color::Error))
 8934                            .cursor_default()
 8935                            .hoverable_tooltip(move |_window, cx| {
 8936                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8937                            })
 8938                    })
 8939                    .children(keybind),
 8940            )
 8941            .into_any();
 8942
 8943        let longest_row =
 8944            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8945        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8946            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8947        } else {
 8948            layout_line(
 8949                longest_row,
 8950                editor_snapshot,
 8951                style,
 8952                editor_width,
 8953                |_| false,
 8954                window,
 8955                cx,
 8956            )
 8957            .width
 8958        };
 8959
 8960        let viewport_bounds =
 8961            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8962                right: -right_margin,
 8963                ..Default::default()
 8964            });
 8965
 8966        let x_after_longest =
 8967            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8968                - scroll_pixel_position.x;
 8969
 8970        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8971
 8972        // Fully visible if it can be displayed within the window (allow overlapping other
 8973        // panes). However, this is only allowed if the popover starts within text_bounds.
 8974        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8975            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8976
 8977        let mut origin = if can_position_to_the_right {
 8978            point(
 8979                x_after_longest,
 8980                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8981                    - scroll_pixel_position.y,
 8982            )
 8983        } else {
 8984            let cursor_row = newest_selection_head.map(|head| head.row());
 8985            let above_edit = edit_start
 8986                .row()
 8987                .0
 8988                .checked_sub(line_count as u32)
 8989                .map(DisplayRow);
 8990            let below_edit = Some(edit_end.row() + 1);
 8991            let above_cursor =
 8992                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8993            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8994
 8995            // Place the edit popover adjacent to the edit if there is a location
 8996            // available that is onscreen and does not obscure the cursor. Otherwise,
 8997            // place it adjacent to the cursor.
 8998            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8999                .into_iter()
 9000                .flatten()
 9001                .find(|&start_row| {
 9002                    let end_row = start_row + line_count as u32;
 9003                    visible_row_range.contains(&start_row)
 9004                        && visible_row_range.contains(&end_row)
 9005                        && cursor_row
 9006                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9007                })?;
 9008
 9009            content_origin
 9010                + point(
 9011                    -scroll_pixel_position.x,
 9012                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9013                )
 9014        };
 9015
 9016        origin.x -= BORDER_WIDTH;
 9017
 9018        window.defer_draw(element, origin, 1);
 9019
 9020        // Do not return an element, since it will already be drawn due to defer_draw.
 9021        None
 9022    }
 9023
 9024    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9025        px(30.)
 9026    }
 9027
 9028    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9029        if self.read_only(cx) {
 9030            cx.theme().players().read_only()
 9031        } else {
 9032            self.style.as_ref().unwrap().local_player
 9033        }
 9034    }
 9035
 9036    fn render_edit_prediction_accept_keybind(
 9037        &self,
 9038        window: &mut Window,
 9039        cx: &App,
 9040    ) -> Option<AnyElement> {
 9041        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9042        let accept_keystroke = accept_binding.keystroke()?;
 9043
 9044        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9045
 9046        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9047            Color::Accent
 9048        } else {
 9049            Color::Muted
 9050        };
 9051
 9052        h_flex()
 9053            .px_0p5()
 9054            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9055            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9056            .text_size(TextSize::XSmall.rems(cx))
 9057            .child(h_flex().children(ui::render_modifiers(
 9058                accept_keystroke.modifiers(),
 9059                PlatformStyle::platform(),
 9060                Some(modifiers_color),
 9061                Some(IconSize::XSmall.rems().into()),
 9062                true,
 9063            )))
 9064            .when(is_platform_style_mac, |parent| {
 9065                parent.child(accept_keystroke.key().to_string())
 9066            })
 9067            .when(!is_platform_style_mac, |parent| {
 9068                parent.child(
 9069                    Key::new(
 9070                        util::capitalize(accept_keystroke.key()),
 9071                        Some(Color::Default),
 9072                    )
 9073                    .size(Some(IconSize::XSmall.rems().into())),
 9074                )
 9075            })
 9076            .into_any()
 9077            .into()
 9078    }
 9079
 9080    fn render_edit_prediction_line_popover(
 9081        &self,
 9082        label: impl Into<SharedString>,
 9083        icon: Option<IconName>,
 9084        window: &mut Window,
 9085        cx: &App,
 9086    ) -> Option<Stateful<Div>> {
 9087        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9088
 9089        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9090        let has_keybind = keybind.is_some();
 9091
 9092        let result = h_flex()
 9093            .id("ep-line-popover")
 9094            .py_0p5()
 9095            .pl_1()
 9096            .pr(padding_right)
 9097            .gap_1()
 9098            .rounded_md()
 9099            .border_1()
 9100            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9101            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9102            .shadow_xs()
 9103            .when(!has_keybind, |el| {
 9104                let status_colors = cx.theme().status();
 9105
 9106                el.bg(status_colors.error_background)
 9107                    .border_color(status_colors.error.opacity(0.6))
 9108                    .pl_2()
 9109                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9110                    .cursor_default()
 9111                    .hoverable_tooltip(move |_window, cx| {
 9112                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9113                    })
 9114            })
 9115            .children(keybind)
 9116            .child(
 9117                Label::new(label)
 9118                    .size(LabelSize::Small)
 9119                    .when(!has_keybind, |el| {
 9120                        el.color(cx.theme().status().error.into()).strikethrough()
 9121                    }),
 9122            )
 9123            .when(!has_keybind, |el| {
 9124                el.child(
 9125                    h_flex().ml_1().child(
 9126                        Icon::new(IconName::Info)
 9127                            .size(IconSize::Small)
 9128                            .color(cx.theme().status().error.into()),
 9129                    ),
 9130                )
 9131            })
 9132            .when_some(icon, |element, icon| {
 9133                element.child(
 9134                    div()
 9135                        .mt(px(1.5))
 9136                        .child(Icon::new(icon).size(IconSize::Small)),
 9137                )
 9138            });
 9139
 9140        Some(result)
 9141    }
 9142
 9143    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9144        let accent_color = cx.theme().colors().text_accent;
 9145        let editor_bg_color = cx.theme().colors().editor_background;
 9146        editor_bg_color.blend(accent_color.opacity(0.1))
 9147    }
 9148
 9149    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9150        let accent_color = cx.theme().colors().text_accent;
 9151        let editor_bg_color = cx.theme().colors().editor_background;
 9152        editor_bg_color.blend(accent_color.opacity(0.6))
 9153    }
 9154    fn get_prediction_provider_icon_name(
 9155        provider: &Option<RegisteredEditPredictionProvider>,
 9156    ) -> IconName {
 9157        match provider {
 9158            Some(provider) => match provider.provider.name() {
 9159                "copilot" => IconName::Copilot,
 9160                "supermaven" => IconName::Supermaven,
 9161                _ => IconName::ZedPredict,
 9162            },
 9163            None => IconName::ZedPredict,
 9164        }
 9165    }
 9166
 9167    fn render_edit_prediction_cursor_popover(
 9168        &self,
 9169        min_width: Pixels,
 9170        max_width: Pixels,
 9171        cursor_point: Point,
 9172        style: &EditorStyle,
 9173        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9174        _window: &Window,
 9175        cx: &mut Context<Editor>,
 9176    ) -> Option<AnyElement> {
 9177        let provider = self.edit_prediction_provider.as_ref()?;
 9178        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9179
 9180        let is_refreshing = provider.provider.is_refreshing(cx);
 9181
 9182        fn pending_completion_container(icon: IconName) -> Div {
 9183            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9184        }
 9185
 9186        let completion = match &self.active_edit_prediction {
 9187            Some(prediction) => {
 9188                if !self.has_visible_completions_menu() {
 9189                    const RADIUS: Pixels = px(6.);
 9190                    const BORDER_WIDTH: Pixels = px(1.);
 9191
 9192                    return Some(
 9193                        h_flex()
 9194                            .elevation_2(cx)
 9195                            .border(BORDER_WIDTH)
 9196                            .border_color(cx.theme().colors().border)
 9197                            .when(accept_keystroke.is_none(), |el| {
 9198                                el.border_color(cx.theme().status().error)
 9199                            })
 9200                            .rounded(RADIUS)
 9201                            .rounded_tl(px(0.))
 9202                            .overflow_hidden()
 9203                            .child(div().px_1p5().child(match &prediction.completion {
 9204                                EditPrediction::Move { target, snapshot } => {
 9205                                    use text::ToPoint as _;
 9206                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9207                                    {
 9208                                        Icon::new(IconName::ZedPredictDown)
 9209                                    } else {
 9210                                        Icon::new(IconName::ZedPredictUp)
 9211                                    }
 9212                                }
 9213                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9214                            }))
 9215                            .child(
 9216                                h_flex()
 9217                                    .gap_1()
 9218                                    .py_1()
 9219                                    .px_2()
 9220                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9221                                    .border_l_1()
 9222                                    .border_color(cx.theme().colors().border)
 9223                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9224                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9225                                        el.child(
 9226                                            Label::new("Hold")
 9227                                                .size(LabelSize::Small)
 9228                                                .when(accept_keystroke.is_none(), |el| {
 9229                                                    el.strikethrough()
 9230                                                })
 9231                                                .line_height_style(LineHeightStyle::UiLabel),
 9232                                        )
 9233                                    })
 9234                                    .id("edit_prediction_cursor_popover_keybind")
 9235                                    .when(accept_keystroke.is_none(), |el| {
 9236                                        let status_colors = cx.theme().status();
 9237
 9238                                        el.bg(status_colors.error_background)
 9239                                            .border_color(status_colors.error.opacity(0.6))
 9240                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9241                                            .cursor_default()
 9242                                            .hoverable_tooltip(move |_window, cx| {
 9243                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9244                                                    .into()
 9245                                            })
 9246                                    })
 9247                                    .when_some(
 9248                                        accept_keystroke.as_ref(),
 9249                                        |el, accept_keystroke| {
 9250                                            el.child(h_flex().children(ui::render_modifiers(
 9251                                                accept_keystroke.modifiers(),
 9252                                                PlatformStyle::platform(),
 9253                                                Some(Color::Default),
 9254                                                Some(IconSize::XSmall.rems().into()),
 9255                                                false,
 9256                                            )))
 9257                                        },
 9258                                    ),
 9259                            )
 9260                            .into_any(),
 9261                    );
 9262                }
 9263
 9264                self.render_edit_prediction_cursor_popover_preview(
 9265                    prediction,
 9266                    cursor_point,
 9267                    style,
 9268                    cx,
 9269                )?
 9270            }
 9271
 9272            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9273                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9274                    stale_completion,
 9275                    cursor_point,
 9276                    style,
 9277                    cx,
 9278                )?,
 9279
 9280                None => pending_completion_container(provider_icon)
 9281                    .child(Label::new("...").size(LabelSize::Small)),
 9282            },
 9283
 9284            None => pending_completion_container(provider_icon)
 9285                .child(Label::new("...").size(LabelSize::Small)),
 9286        };
 9287
 9288        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9289            completion
 9290                .with_animation(
 9291                    "loading-completion",
 9292                    Animation::new(Duration::from_secs(2))
 9293                        .repeat()
 9294                        .with_easing(pulsating_between(0.4, 0.8)),
 9295                    |label, delta| label.opacity(delta),
 9296                )
 9297                .into_any_element()
 9298        } else {
 9299            completion.into_any_element()
 9300        };
 9301
 9302        let has_completion = self.active_edit_prediction.is_some();
 9303
 9304        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9305        Some(
 9306            h_flex()
 9307                .min_w(min_width)
 9308                .max_w(max_width)
 9309                .flex_1()
 9310                .elevation_2(cx)
 9311                .border_color(cx.theme().colors().border)
 9312                .child(
 9313                    div()
 9314                        .flex_1()
 9315                        .py_1()
 9316                        .px_2()
 9317                        .overflow_hidden()
 9318                        .child(completion),
 9319                )
 9320                .when_some(accept_keystroke, |el, accept_keystroke| {
 9321                    if !accept_keystroke.modifiers().modified() {
 9322                        return el;
 9323                    }
 9324
 9325                    el.child(
 9326                        h_flex()
 9327                            .h_full()
 9328                            .border_l_1()
 9329                            .rounded_r_lg()
 9330                            .border_color(cx.theme().colors().border)
 9331                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9332                            .gap_1()
 9333                            .py_1()
 9334                            .px_2()
 9335                            .child(
 9336                                h_flex()
 9337                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9338                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9339                                    .child(h_flex().children(ui::render_modifiers(
 9340                                        accept_keystroke.modifiers(),
 9341                                        PlatformStyle::platform(),
 9342                                        Some(if !has_completion {
 9343                                            Color::Muted
 9344                                        } else {
 9345                                            Color::Default
 9346                                        }),
 9347                                        None,
 9348                                        false,
 9349                                    ))),
 9350                            )
 9351                            .child(Label::new("Preview").into_any_element())
 9352                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9353                    )
 9354                })
 9355                .into_any(),
 9356        )
 9357    }
 9358
 9359    fn render_edit_prediction_cursor_popover_preview(
 9360        &self,
 9361        completion: &EditPredictionState,
 9362        cursor_point: Point,
 9363        style: &EditorStyle,
 9364        cx: &mut Context<Editor>,
 9365    ) -> Option<Div> {
 9366        use text::ToPoint as _;
 9367
 9368        fn render_relative_row_jump(
 9369            prefix: impl Into<String>,
 9370            current_row: u32,
 9371            target_row: u32,
 9372        ) -> Div {
 9373            let (row_diff, arrow) = if target_row < current_row {
 9374                (current_row - target_row, IconName::ArrowUp)
 9375            } else {
 9376                (target_row - current_row, IconName::ArrowDown)
 9377            };
 9378
 9379            h_flex()
 9380                .child(
 9381                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9382                        .color(Color::Muted)
 9383                        .size(LabelSize::Small),
 9384                )
 9385                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9386        }
 9387
 9388        let supports_jump = self
 9389            .edit_prediction_provider
 9390            .as_ref()
 9391            .map(|provider| provider.provider.supports_jump_to_edit())
 9392            .unwrap_or(true);
 9393
 9394        match &completion.completion {
 9395            EditPrediction::Move {
 9396                target, snapshot, ..
 9397            } => {
 9398                if !supports_jump {
 9399                    return None;
 9400                }
 9401
 9402                Some(
 9403                    h_flex()
 9404                        .px_2()
 9405                        .gap_2()
 9406                        .flex_1()
 9407                        .child(
 9408                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9409                                Icon::new(IconName::ZedPredictDown)
 9410                            } else {
 9411                                Icon::new(IconName::ZedPredictUp)
 9412                            },
 9413                        )
 9414                        .child(Label::new("Jump to Edit")),
 9415                )
 9416            }
 9417
 9418            EditPrediction::Edit {
 9419                edits,
 9420                edit_preview,
 9421                snapshot,
 9422                display_mode: _,
 9423            } => {
 9424                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9425
 9426                let (highlighted_edits, has_more_lines) =
 9427                    if let Some(edit_preview) = edit_preview.as_ref() {
 9428                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9429                            .first_line_preview()
 9430                    } else {
 9431                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9432                    };
 9433
 9434                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9435                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9436
 9437                let preview = h_flex()
 9438                    .gap_1()
 9439                    .min_w_16()
 9440                    .child(styled_text)
 9441                    .when(has_more_lines, |parent| parent.child(""));
 9442
 9443                let left = if supports_jump && first_edit_row != cursor_point.row {
 9444                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9445                        .into_any_element()
 9446                } else {
 9447                    let icon_name =
 9448                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9449                    Icon::new(icon_name).into_any_element()
 9450                };
 9451
 9452                Some(
 9453                    h_flex()
 9454                        .h_full()
 9455                        .flex_1()
 9456                        .gap_2()
 9457                        .pr_1()
 9458                        .overflow_x_hidden()
 9459                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9460                        .child(left)
 9461                        .child(preview),
 9462                )
 9463            }
 9464        }
 9465    }
 9466
 9467    pub fn render_context_menu(
 9468        &self,
 9469        style: &EditorStyle,
 9470        max_height_in_lines: u32,
 9471        window: &mut Window,
 9472        cx: &mut Context<Editor>,
 9473    ) -> Option<AnyElement> {
 9474        let menu = self.context_menu.borrow();
 9475        let menu = menu.as_ref()?;
 9476        if !menu.visible() {
 9477            return None;
 9478        };
 9479        Some(menu.render(style, max_height_in_lines, window, cx))
 9480    }
 9481
 9482    fn render_context_menu_aside(
 9483        &mut self,
 9484        max_size: Size<Pixels>,
 9485        window: &mut Window,
 9486        cx: &mut Context<Editor>,
 9487    ) -> Option<AnyElement> {
 9488        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9489            if menu.visible() {
 9490                menu.render_aside(max_size, window, cx)
 9491            } else {
 9492                None
 9493            }
 9494        })
 9495    }
 9496
 9497    fn hide_context_menu(
 9498        &mut self,
 9499        window: &mut Window,
 9500        cx: &mut Context<Self>,
 9501    ) -> Option<CodeContextMenu> {
 9502        cx.notify();
 9503        self.completion_tasks.clear();
 9504        let context_menu = self.context_menu.borrow_mut().take();
 9505        self.stale_edit_prediction_in_menu.take();
 9506        self.update_visible_edit_prediction(window, cx);
 9507        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9508            && let Some(completion_provider) = &self.completion_provider
 9509        {
 9510            completion_provider.selection_changed(None, window, cx);
 9511        }
 9512        context_menu
 9513    }
 9514
 9515    fn show_snippet_choices(
 9516        &mut self,
 9517        choices: &Vec<String>,
 9518        selection: Range<Anchor>,
 9519        cx: &mut Context<Self>,
 9520    ) {
 9521        let Some((_, buffer, _)) = self
 9522            .buffer()
 9523            .read(cx)
 9524            .excerpt_containing(selection.start, cx)
 9525        else {
 9526            return;
 9527        };
 9528        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9529        else {
 9530            return;
 9531        };
 9532        if buffer != end_buffer {
 9533            log::error!("expected anchor range to have matching buffer IDs");
 9534            return;
 9535        }
 9536
 9537        let id = post_inc(&mut self.next_completion_id);
 9538        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9539        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9540            CompletionsMenu::new_snippet_choices(
 9541                id,
 9542                true,
 9543                choices,
 9544                selection,
 9545                buffer,
 9546                snippet_sort_order,
 9547            ),
 9548        ));
 9549    }
 9550
 9551    pub fn insert_snippet(
 9552        &mut self,
 9553        insertion_ranges: &[Range<usize>],
 9554        snippet: Snippet,
 9555        window: &mut Window,
 9556        cx: &mut Context<Self>,
 9557    ) -> Result<()> {
 9558        struct Tabstop<T> {
 9559            is_end_tabstop: bool,
 9560            ranges: Vec<Range<T>>,
 9561            choices: Option<Vec<String>>,
 9562        }
 9563
 9564        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9565            let snippet_text: Arc<str> = snippet.text.clone().into();
 9566            let edits = insertion_ranges
 9567                .iter()
 9568                .cloned()
 9569                .map(|range| (range, snippet_text.clone()));
 9570            let autoindent_mode = AutoindentMode::Block {
 9571                original_indent_columns: Vec::new(),
 9572            };
 9573            buffer.edit(edits, Some(autoindent_mode), cx);
 9574
 9575            let snapshot = &*buffer.read(cx);
 9576            let snippet = &snippet;
 9577            snippet
 9578                .tabstops
 9579                .iter()
 9580                .map(|tabstop| {
 9581                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9582                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9583                    });
 9584                    let mut tabstop_ranges = tabstop
 9585                        .ranges
 9586                        .iter()
 9587                        .flat_map(|tabstop_range| {
 9588                            let mut delta = 0_isize;
 9589                            insertion_ranges.iter().map(move |insertion_range| {
 9590                                let insertion_start = insertion_range.start as isize + delta;
 9591                                delta +=
 9592                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9593
 9594                                let start = ((insertion_start + tabstop_range.start) as usize)
 9595                                    .min(snapshot.len());
 9596                                let end = ((insertion_start + tabstop_range.end) as usize)
 9597                                    .min(snapshot.len());
 9598                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9599                            })
 9600                        })
 9601                        .collect::<Vec<_>>();
 9602                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9603
 9604                    Tabstop {
 9605                        is_end_tabstop,
 9606                        ranges: tabstop_ranges,
 9607                        choices: tabstop.choices.clone(),
 9608                    }
 9609                })
 9610                .collect::<Vec<_>>()
 9611        });
 9612        if let Some(tabstop) = tabstops.first() {
 9613            self.change_selections(Default::default(), window, cx, |s| {
 9614                // Reverse order so that the first range is the newest created selection.
 9615                // Completions will use it and autoscroll will prioritize it.
 9616                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9617            });
 9618
 9619            if let Some(choices) = &tabstop.choices
 9620                && let Some(selection) = tabstop.ranges.first()
 9621            {
 9622                self.show_snippet_choices(choices, selection.clone(), cx)
 9623            }
 9624
 9625            // If we're already at the last tabstop and it's at the end of the snippet,
 9626            // we're done, we don't need to keep the state around.
 9627            if !tabstop.is_end_tabstop {
 9628                let choices = tabstops
 9629                    .iter()
 9630                    .map(|tabstop| tabstop.choices.clone())
 9631                    .collect();
 9632
 9633                let ranges = tabstops
 9634                    .into_iter()
 9635                    .map(|tabstop| tabstop.ranges)
 9636                    .collect::<Vec<_>>();
 9637
 9638                self.snippet_stack.push(SnippetState {
 9639                    active_index: 0,
 9640                    ranges,
 9641                    choices,
 9642                });
 9643            }
 9644
 9645            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9646            if self.autoclose_regions.is_empty() {
 9647                let snapshot = self.buffer.read(cx).snapshot(cx);
 9648                let mut all_selections = self.selections.all::<Point>(cx);
 9649                for selection in &mut all_selections {
 9650                    let selection_head = selection.head();
 9651                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9652                        continue;
 9653                    };
 9654
 9655                    let mut bracket_pair = None;
 9656                    let max_lookup_length = scope
 9657                        .brackets()
 9658                        .map(|(pair, _)| {
 9659                            pair.start
 9660                                .as_str()
 9661                                .chars()
 9662                                .count()
 9663                                .max(pair.end.as_str().chars().count())
 9664                        })
 9665                        .max();
 9666                    if let Some(max_lookup_length) = max_lookup_length {
 9667                        let next_text = snapshot
 9668                            .chars_at(selection_head)
 9669                            .take(max_lookup_length)
 9670                            .collect::<String>();
 9671                        let prev_text = snapshot
 9672                            .reversed_chars_at(selection_head)
 9673                            .take(max_lookup_length)
 9674                            .collect::<String>();
 9675
 9676                        for (pair, enabled) in scope.brackets() {
 9677                            if enabled
 9678                                && pair.close
 9679                                && prev_text.starts_with(pair.start.as_str())
 9680                                && next_text.starts_with(pair.end.as_str())
 9681                            {
 9682                                bracket_pair = Some(pair.clone());
 9683                                break;
 9684                            }
 9685                        }
 9686                    }
 9687
 9688                    if let Some(pair) = bracket_pair {
 9689                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9690                        let autoclose_enabled =
 9691                            self.use_autoclose && snapshot_settings.use_autoclose;
 9692                        if autoclose_enabled {
 9693                            let start = snapshot.anchor_after(selection_head);
 9694                            let end = snapshot.anchor_after(selection_head);
 9695                            self.autoclose_regions.push(AutocloseRegion {
 9696                                selection_id: selection.id,
 9697                                range: start..end,
 9698                                pair,
 9699                            });
 9700                        }
 9701                    }
 9702                }
 9703            }
 9704        }
 9705        Ok(())
 9706    }
 9707
 9708    pub fn move_to_next_snippet_tabstop(
 9709        &mut self,
 9710        window: &mut Window,
 9711        cx: &mut Context<Self>,
 9712    ) -> bool {
 9713        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9714    }
 9715
 9716    pub fn move_to_prev_snippet_tabstop(
 9717        &mut self,
 9718        window: &mut Window,
 9719        cx: &mut Context<Self>,
 9720    ) -> bool {
 9721        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9722    }
 9723
 9724    pub fn move_to_snippet_tabstop(
 9725        &mut self,
 9726        bias: Bias,
 9727        window: &mut Window,
 9728        cx: &mut Context<Self>,
 9729    ) -> bool {
 9730        if let Some(mut snippet) = self.snippet_stack.pop() {
 9731            match bias {
 9732                Bias::Left => {
 9733                    if snippet.active_index > 0 {
 9734                        snippet.active_index -= 1;
 9735                    } else {
 9736                        self.snippet_stack.push(snippet);
 9737                        return false;
 9738                    }
 9739                }
 9740                Bias::Right => {
 9741                    if snippet.active_index + 1 < snippet.ranges.len() {
 9742                        snippet.active_index += 1;
 9743                    } else {
 9744                        self.snippet_stack.push(snippet);
 9745                        return false;
 9746                    }
 9747                }
 9748            }
 9749            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9750                self.change_selections(Default::default(), window, cx, |s| {
 9751                    // Reverse order so that the first range is the newest created selection.
 9752                    // Completions will use it and autoscroll will prioritize it.
 9753                    s.select_ranges(current_ranges.iter().rev().cloned())
 9754                });
 9755
 9756                if let Some(choices) = &snippet.choices[snippet.active_index]
 9757                    && let Some(selection) = current_ranges.first()
 9758                {
 9759                    self.show_snippet_choices(choices, selection.clone(), cx);
 9760                }
 9761
 9762                // If snippet state is not at the last tabstop, push it back on the stack
 9763                if snippet.active_index + 1 < snippet.ranges.len() {
 9764                    self.snippet_stack.push(snippet);
 9765                }
 9766                return true;
 9767            }
 9768        }
 9769
 9770        false
 9771    }
 9772
 9773    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9774        self.transact(window, cx, |this, window, cx| {
 9775            this.select_all(&SelectAll, window, cx);
 9776            this.insert("", window, cx);
 9777        });
 9778    }
 9779
 9780    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9781        if self.read_only(cx) {
 9782            return;
 9783        }
 9784        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9785        self.transact(window, cx, |this, window, cx| {
 9786            this.select_autoclose_pair(window, cx);
 9787            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9788            if !this.linked_edit_ranges.is_empty() {
 9789                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9790                let snapshot = this.buffer.read(cx).snapshot(cx);
 9791
 9792                for selection in selections.iter() {
 9793                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9794                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9795                    if selection_start.buffer_id != selection_end.buffer_id {
 9796                        continue;
 9797                    }
 9798                    if let Some(ranges) =
 9799                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9800                    {
 9801                        for (buffer, entries) in ranges {
 9802                            linked_ranges.entry(buffer).or_default().extend(entries);
 9803                        }
 9804                    }
 9805                }
 9806            }
 9807
 9808            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9809            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9810            for selection in &mut selections {
 9811                if selection.is_empty() {
 9812                    let old_head = selection.head();
 9813                    let mut new_head =
 9814                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9815                            .to_point(&display_map);
 9816                    if let Some((buffer, line_buffer_range)) = display_map
 9817                        .buffer_snapshot
 9818                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9819                    {
 9820                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9821                        let indent_len = match indent_size.kind {
 9822                            IndentKind::Space => {
 9823                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9824                            }
 9825                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9826                        };
 9827                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9828                            let indent_len = indent_len.get();
 9829                            new_head = cmp::min(
 9830                                new_head,
 9831                                MultiBufferPoint::new(
 9832                                    old_head.row,
 9833                                    ((old_head.column - 1) / indent_len) * indent_len,
 9834                                ),
 9835                            );
 9836                        }
 9837                    }
 9838
 9839                    selection.set_head(new_head, SelectionGoal::None);
 9840                }
 9841            }
 9842
 9843            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9844            this.insert("", window, cx);
 9845            let empty_str: Arc<str> = Arc::from("");
 9846            for (buffer, edits) in linked_ranges {
 9847                let snapshot = buffer.read(cx).snapshot();
 9848                use text::ToPoint as TP;
 9849
 9850                let edits = edits
 9851                    .into_iter()
 9852                    .map(|range| {
 9853                        let end_point = TP::to_point(&range.end, &snapshot);
 9854                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9855
 9856                        if end_point == start_point {
 9857                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9858                                .saturating_sub(1);
 9859                            start_point =
 9860                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9861                        };
 9862
 9863                        (start_point..end_point, empty_str.clone())
 9864                    })
 9865                    .sorted_by_key(|(range, _)| range.start)
 9866                    .collect::<Vec<_>>();
 9867                buffer.update(cx, |this, cx| {
 9868                    this.edit(edits, None, cx);
 9869                })
 9870            }
 9871            this.refresh_edit_prediction(true, false, window, cx);
 9872            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9873        });
 9874    }
 9875
 9876    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9877        if self.read_only(cx) {
 9878            return;
 9879        }
 9880        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9881        self.transact(window, cx, |this, window, cx| {
 9882            this.change_selections(Default::default(), window, cx, |s| {
 9883                s.move_with(|map, selection| {
 9884                    if selection.is_empty() {
 9885                        let cursor = movement::right(map, selection.head());
 9886                        selection.end = cursor;
 9887                        selection.reversed = true;
 9888                        selection.goal = SelectionGoal::None;
 9889                    }
 9890                })
 9891            });
 9892            this.insert("", window, cx);
 9893            this.refresh_edit_prediction(true, false, window, cx);
 9894        });
 9895    }
 9896
 9897    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9898        if self.mode.is_single_line() {
 9899            cx.propagate();
 9900            return;
 9901        }
 9902
 9903        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9904        if self.move_to_prev_snippet_tabstop(window, cx) {
 9905            return;
 9906        }
 9907        self.outdent(&Outdent, window, cx);
 9908    }
 9909
 9910    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9911        if self.mode.is_single_line() {
 9912            cx.propagate();
 9913            return;
 9914        }
 9915
 9916        if self.move_to_next_snippet_tabstop(window, cx) {
 9917            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9918            return;
 9919        }
 9920        if self.read_only(cx) {
 9921            return;
 9922        }
 9923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9924        let mut selections = self.selections.all_adjusted(cx);
 9925        let buffer = self.buffer.read(cx);
 9926        let snapshot = buffer.snapshot(cx);
 9927        let rows_iter = selections.iter().map(|s| s.head().row);
 9928        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9929
 9930        let has_some_cursor_in_whitespace = selections
 9931            .iter()
 9932            .filter(|selection| selection.is_empty())
 9933            .any(|selection| {
 9934                let cursor = selection.head();
 9935                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9936                cursor.column < current_indent.len
 9937            });
 9938
 9939        let mut edits = Vec::new();
 9940        let mut prev_edited_row = 0;
 9941        let mut row_delta = 0;
 9942        for selection in &mut selections {
 9943            if selection.start.row != prev_edited_row {
 9944                row_delta = 0;
 9945            }
 9946            prev_edited_row = selection.end.row;
 9947
 9948            // If the selection is non-empty, then increase the indentation of the selected lines.
 9949            if !selection.is_empty() {
 9950                row_delta =
 9951                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9952                continue;
 9953            }
 9954
 9955            let cursor = selection.head();
 9956            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9957            if let Some(suggested_indent) =
 9958                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9959            {
 9960                // Don't do anything if already at suggested indent
 9961                // and there is any other cursor which is not
 9962                if has_some_cursor_in_whitespace
 9963                    && cursor.column == current_indent.len
 9964                    && current_indent.len == suggested_indent.len
 9965                {
 9966                    continue;
 9967                }
 9968
 9969                // Adjust line and move cursor to suggested indent
 9970                // if cursor is not at suggested indent
 9971                if cursor.column < suggested_indent.len
 9972                    && cursor.column <= current_indent.len
 9973                    && current_indent.len <= suggested_indent.len
 9974                {
 9975                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9976                    selection.end = selection.start;
 9977                    if row_delta == 0 {
 9978                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9979                            cursor.row,
 9980                            current_indent,
 9981                            suggested_indent,
 9982                        ));
 9983                        row_delta = suggested_indent.len - current_indent.len;
 9984                    }
 9985                    continue;
 9986                }
 9987
 9988                // If current indent is more than suggested indent
 9989                // only move cursor to current indent and skip indent
 9990                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9991                    selection.start = Point::new(cursor.row, current_indent.len);
 9992                    selection.end = selection.start;
 9993                    continue;
 9994                }
 9995            }
 9996
 9997            // Otherwise, insert a hard or soft tab.
 9998            let settings = buffer.language_settings_at(cursor, cx);
 9999            let tab_size = if settings.hard_tabs {
10000                IndentSize::tab()
10001            } else {
10002                let tab_size = settings.tab_size.get();
10003                let indent_remainder = snapshot
10004                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10005                    .flat_map(str::chars)
10006                    .fold(row_delta % tab_size, |counter: u32, c| {
10007                        if c == '\t' {
10008                            0
10009                        } else {
10010                            (counter + 1) % tab_size
10011                        }
10012                    });
10013
10014                let chars_to_next_tab_stop = tab_size - indent_remainder;
10015                IndentSize::spaces(chars_to_next_tab_stop)
10016            };
10017            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10018            selection.end = selection.start;
10019            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10020            row_delta += tab_size.len;
10021        }
10022
10023        self.transact(window, cx, |this, window, cx| {
10024            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10025            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10026            this.refresh_edit_prediction(true, false, window, cx);
10027        });
10028    }
10029
10030    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10031        if self.read_only(cx) {
10032            return;
10033        }
10034        if self.mode.is_single_line() {
10035            cx.propagate();
10036            return;
10037        }
10038
10039        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10040        let mut selections = self.selections.all::<Point>(cx);
10041        let mut prev_edited_row = 0;
10042        let mut row_delta = 0;
10043        let mut edits = Vec::new();
10044        let buffer = self.buffer.read(cx);
10045        let snapshot = buffer.snapshot(cx);
10046        for selection in &mut selections {
10047            if selection.start.row != prev_edited_row {
10048                row_delta = 0;
10049            }
10050            prev_edited_row = selection.end.row;
10051
10052            row_delta =
10053                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10054        }
10055
10056        self.transact(window, cx, |this, window, cx| {
10057            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10058            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10059        });
10060    }
10061
10062    fn indent_selection(
10063        buffer: &MultiBuffer,
10064        snapshot: &MultiBufferSnapshot,
10065        selection: &mut Selection<Point>,
10066        edits: &mut Vec<(Range<Point>, String)>,
10067        delta_for_start_row: u32,
10068        cx: &App,
10069    ) -> u32 {
10070        let settings = buffer.language_settings_at(selection.start, cx);
10071        let tab_size = settings.tab_size.get();
10072        let indent_kind = if settings.hard_tabs {
10073            IndentKind::Tab
10074        } else {
10075            IndentKind::Space
10076        };
10077        let mut start_row = selection.start.row;
10078        let mut end_row = selection.end.row + 1;
10079
10080        // If a selection ends at the beginning of a line, don't indent
10081        // that last line.
10082        if selection.end.column == 0 && selection.end.row > selection.start.row {
10083            end_row -= 1;
10084        }
10085
10086        // Avoid re-indenting a row that has already been indented by a
10087        // previous selection, but still update this selection's column
10088        // to reflect that indentation.
10089        if delta_for_start_row > 0 {
10090            start_row += 1;
10091            selection.start.column += delta_for_start_row;
10092            if selection.end.row == selection.start.row {
10093                selection.end.column += delta_for_start_row;
10094            }
10095        }
10096
10097        let mut delta_for_end_row = 0;
10098        let has_multiple_rows = start_row + 1 != end_row;
10099        for row in start_row..end_row {
10100            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10101            let indent_delta = match (current_indent.kind, indent_kind) {
10102                (IndentKind::Space, IndentKind::Space) => {
10103                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10104                    IndentSize::spaces(columns_to_next_tab_stop)
10105                }
10106                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10107                (_, IndentKind::Tab) => IndentSize::tab(),
10108            };
10109
10110            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10111                0
10112            } else {
10113                selection.start.column
10114            };
10115            let row_start = Point::new(row, start);
10116            edits.push((
10117                row_start..row_start,
10118                indent_delta.chars().collect::<String>(),
10119            ));
10120
10121            // Update this selection's endpoints to reflect the indentation.
10122            if row == selection.start.row {
10123                selection.start.column += indent_delta.len;
10124            }
10125            if row == selection.end.row {
10126                selection.end.column += indent_delta.len;
10127                delta_for_end_row = indent_delta.len;
10128            }
10129        }
10130
10131        if selection.start.row == selection.end.row {
10132            delta_for_start_row + delta_for_end_row
10133        } else {
10134            delta_for_end_row
10135        }
10136    }
10137
10138    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10139        if self.read_only(cx) {
10140            return;
10141        }
10142        if self.mode.is_single_line() {
10143            cx.propagate();
10144            return;
10145        }
10146
10147        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10148        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10149        let selections = self.selections.all::<Point>(cx);
10150        let mut deletion_ranges = Vec::new();
10151        let mut last_outdent = None;
10152        {
10153            let buffer = self.buffer.read(cx);
10154            let snapshot = buffer.snapshot(cx);
10155            for selection in &selections {
10156                let settings = buffer.language_settings_at(selection.start, cx);
10157                let tab_size = settings.tab_size.get();
10158                let mut rows = selection.spanned_rows(false, &display_map);
10159
10160                // Avoid re-outdenting a row that has already been outdented by a
10161                // previous selection.
10162                if let Some(last_row) = last_outdent
10163                    && last_row == rows.start
10164                {
10165                    rows.start = rows.start.next_row();
10166                }
10167                let has_multiple_rows = rows.len() > 1;
10168                for row in rows.iter_rows() {
10169                    let indent_size = snapshot.indent_size_for_line(row);
10170                    if indent_size.len > 0 {
10171                        let deletion_len = match indent_size.kind {
10172                            IndentKind::Space => {
10173                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10174                                if columns_to_prev_tab_stop == 0 {
10175                                    tab_size
10176                                } else {
10177                                    columns_to_prev_tab_stop
10178                                }
10179                            }
10180                            IndentKind::Tab => 1,
10181                        };
10182                        let start = if has_multiple_rows
10183                            || deletion_len > selection.start.column
10184                            || indent_size.len < selection.start.column
10185                        {
10186                            0
10187                        } else {
10188                            selection.start.column - deletion_len
10189                        };
10190                        deletion_ranges.push(
10191                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10192                        );
10193                        last_outdent = Some(row);
10194                    }
10195                }
10196            }
10197        }
10198
10199        self.transact(window, cx, |this, window, cx| {
10200            this.buffer.update(cx, |buffer, cx| {
10201                let empty_str: Arc<str> = Arc::default();
10202                buffer.edit(
10203                    deletion_ranges
10204                        .into_iter()
10205                        .map(|range| (range, empty_str.clone())),
10206                    None,
10207                    cx,
10208                );
10209            });
10210            let selections = this.selections.all::<usize>(cx);
10211            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10212        });
10213    }
10214
10215    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10216        if self.read_only(cx) {
10217            return;
10218        }
10219        if self.mode.is_single_line() {
10220            cx.propagate();
10221            return;
10222        }
10223
10224        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10225        let selections = self
10226            .selections
10227            .all::<usize>(cx)
10228            .into_iter()
10229            .map(|s| s.range());
10230
10231        self.transact(window, cx, |this, window, cx| {
10232            this.buffer.update(cx, |buffer, cx| {
10233                buffer.autoindent_ranges(selections, cx);
10234            });
10235            let selections = this.selections.all::<usize>(cx);
10236            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10237        });
10238    }
10239
10240    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10241        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10242        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10243        let selections = self.selections.all::<Point>(cx);
10244
10245        let mut new_cursors = Vec::new();
10246        let mut edit_ranges = Vec::new();
10247        let mut selections = selections.iter().peekable();
10248        while let Some(selection) = selections.next() {
10249            let mut rows = selection.spanned_rows(false, &display_map);
10250            let goal_display_column = selection.head().to_display_point(&display_map).column();
10251
10252            // Accumulate contiguous regions of rows that we want to delete.
10253            while let Some(next_selection) = selections.peek() {
10254                let next_rows = next_selection.spanned_rows(false, &display_map);
10255                if next_rows.start <= rows.end {
10256                    rows.end = next_rows.end;
10257                    selections.next().unwrap();
10258                } else {
10259                    break;
10260                }
10261            }
10262
10263            let buffer = &display_map.buffer_snapshot;
10264            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10265            let edit_end;
10266            let cursor_buffer_row;
10267            if buffer.max_point().row >= rows.end.0 {
10268                // If there's a line after the range, delete the \n from the end of the row range
10269                // and position the cursor on the next line.
10270                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10271                cursor_buffer_row = rows.end;
10272            } else {
10273                // If there isn't a line after the range, delete the \n from the line before the
10274                // start of the row range and position the cursor there.
10275                edit_start = edit_start.saturating_sub(1);
10276                edit_end = buffer.len();
10277                cursor_buffer_row = rows.start.previous_row();
10278            }
10279
10280            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10281            *cursor.column_mut() =
10282                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10283
10284            new_cursors.push((
10285                selection.id,
10286                buffer.anchor_after(cursor.to_point(&display_map)),
10287            ));
10288            edit_ranges.push(edit_start..edit_end);
10289        }
10290
10291        self.transact(window, cx, |this, window, cx| {
10292            let buffer = this.buffer.update(cx, |buffer, cx| {
10293                let empty_str: Arc<str> = Arc::default();
10294                buffer.edit(
10295                    edit_ranges
10296                        .into_iter()
10297                        .map(|range| (range, empty_str.clone())),
10298                    None,
10299                    cx,
10300                );
10301                buffer.snapshot(cx)
10302            });
10303            let new_selections = new_cursors
10304                .into_iter()
10305                .map(|(id, cursor)| {
10306                    let cursor = cursor.to_point(&buffer);
10307                    Selection {
10308                        id,
10309                        start: cursor,
10310                        end: cursor,
10311                        reversed: false,
10312                        goal: SelectionGoal::None,
10313                    }
10314                })
10315                .collect();
10316
10317            this.change_selections(Default::default(), window, cx, |s| {
10318                s.select(new_selections);
10319            });
10320        });
10321    }
10322
10323    pub fn join_lines_impl(
10324        &mut self,
10325        insert_whitespace: bool,
10326        window: &mut Window,
10327        cx: &mut Context<Self>,
10328    ) {
10329        if self.read_only(cx) {
10330            return;
10331        }
10332        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10333        for selection in self.selections.all::<Point>(cx) {
10334            let start = MultiBufferRow(selection.start.row);
10335            // Treat single line selections as if they include the next line. Otherwise this action
10336            // would do nothing for single line selections individual cursors.
10337            let end = if selection.start.row == selection.end.row {
10338                MultiBufferRow(selection.start.row + 1)
10339            } else {
10340                MultiBufferRow(selection.end.row)
10341            };
10342
10343            if let Some(last_row_range) = row_ranges.last_mut()
10344                && start <= last_row_range.end
10345            {
10346                last_row_range.end = end;
10347                continue;
10348            }
10349            row_ranges.push(start..end);
10350        }
10351
10352        let snapshot = self.buffer.read(cx).snapshot(cx);
10353        let mut cursor_positions = Vec::new();
10354        for row_range in &row_ranges {
10355            let anchor = snapshot.anchor_before(Point::new(
10356                row_range.end.previous_row().0,
10357                snapshot.line_len(row_range.end.previous_row()),
10358            ));
10359            cursor_positions.push(anchor..anchor);
10360        }
10361
10362        self.transact(window, cx, |this, window, cx| {
10363            for row_range in row_ranges.into_iter().rev() {
10364                for row in row_range.iter_rows().rev() {
10365                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10366                    let next_line_row = row.next_row();
10367                    let indent = snapshot.indent_size_for_line(next_line_row);
10368                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10369
10370                    let replace =
10371                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10372                            " "
10373                        } else {
10374                            ""
10375                        };
10376
10377                    this.buffer.update(cx, |buffer, cx| {
10378                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10379                    });
10380                }
10381            }
10382
10383            this.change_selections(Default::default(), window, cx, |s| {
10384                s.select_anchor_ranges(cursor_positions)
10385            });
10386        });
10387    }
10388
10389    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10390        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10391        self.join_lines_impl(true, window, cx);
10392    }
10393
10394    pub fn sort_lines_case_sensitive(
10395        &mut self,
10396        _: &SortLinesCaseSensitive,
10397        window: &mut Window,
10398        cx: &mut Context<Self>,
10399    ) {
10400        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10401    }
10402
10403    pub fn sort_lines_by_length(
10404        &mut self,
10405        _: &SortLinesByLength,
10406        window: &mut Window,
10407        cx: &mut Context<Self>,
10408    ) {
10409        self.manipulate_immutable_lines(window, cx, |lines| {
10410            lines.sort_by_key(|&line| line.chars().count())
10411        })
10412    }
10413
10414    pub fn sort_lines_case_insensitive(
10415        &mut self,
10416        _: &SortLinesCaseInsensitive,
10417        window: &mut Window,
10418        cx: &mut Context<Self>,
10419    ) {
10420        self.manipulate_immutable_lines(window, cx, |lines| {
10421            lines.sort_by_key(|line| line.to_lowercase())
10422        })
10423    }
10424
10425    pub fn unique_lines_case_insensitive(
10426        &mut self,
10427        _: &UniqueLinesCaseInsensitive,
10428        window: &mut Window,
10429        cx: &mut Context<Self>,
10430    ) {
10431        self.manipulate_immutable_lines(window, cx, |lines| {
10432            let mut seen = HashSet::default();
10433            lines.retain(|line| seen.insert(line.to_lowercase()));
10434        })
10435    }
10436
10437    pub fn unique_lines_case_sensitive(
10438        &mut self,
10439        _: &UniqueLinesCaseSensitive,
10440        window: &mut Window,
10441        cx: &mut Context<Self>,
10442    ) {
10443        self.manipulate_immutable_lines(window, cx, |lines| {
10444            let mut seen = HashSet::default();
10445            lines.retain(|line| seen.insert(*line));
10446        })
10447    }
10448
10449    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10450        let snapshot = self.buffer.read(cx).snapshot(cx);
10451        for selection in self.selections.disjoint_anchors().iter() {
10452            if snapshot
10453                .language_at(selection.start)
10454                .and_then(|lang| lang.config().wrap_characters.as_ref())
10455                .is_some()
10456            {
10457                return true;
10458            }
10459        }
10460        false
10461    }
10462
10463    fn wrap_selections_in_tag(
10464        &mut self,
10465        _: &WrapSelectionsInTag,
10466        window: &mut Window,
10467        cx: &mut Context<Self>,
10468    ) {
10469        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10470
10471        let snapshot = self.buffer.read(cx).snapshot(cx);
10472
10473        let mut edits = Vec::new();
10474        let mut boundaries = Vec::new();
10475
10476        for selection in self.selections.all::<Point>(cx).iter() {
10477            let Some(wrap_config) = snapshot
10478                .language_at(selection.start)
10479                .and_then(|lang| lang.config().wrap_characters.clone())
10480            else {
10481                continue;
10482            };
10483
10484            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10485            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10486
10487            let start_before = snapshot.anchor_before(selection.start);
10488            let end_after = snapshot.anchor_after(selection.end);
10489
10490            edits.push((start_before..start_before, open_tag));
10491            edits.push((end_after..end_after, close_tag));
10492
10493            boundaries.push((
10494                start_before,
10495                end_after,
10496                wrap_config.start_prefix.len(),
10497                wrap_config.end_suffix.len(),
10498            ));
10499        }
10500
10501        if edits.is_empty() {
10502            return;
10503        }
10504
10505        self.transact(window, cx, |this, window, cx| {
10506            let buffer = this.buffer.update(cx, |buffer, cx| {
10507                buffer.edit(edits, None, cx);
10508                buffer.snapshot(cx)
10509            });
10510
10511            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10512            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10513                boundaries.into_iter()
10514            {
10515                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10516                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10517                new_selections.push(open_offset..open_offset);
10518                new_selections.push(close_offset..close_offset);
10519            }
10520
10521            this.change_selections(Default::default(), window, cx, |s| {
10522                s.select_ranges(new_selections);
10523            });
10524
10525            this.request_autoscroll(Autoscroll::fit(), cx);
10526        });
10527    }
10528
10529    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10530        let Some(project) = self.project.clone() else {
10531            return;
10532        };
10533        self.reload(project, window, cx)
10534            .detach_and_notify_err(window, cx);
10535    }
10536
10537    pub fn restore_file(
10538        &mut self,
10539        _: &::git::RestoreFile,
10540        window: &mut Window,
10541        cx: &mut Context<Self>,
10542    ) {
10543        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10544        let mut buffer_ids = HashSet::default();
10545        let snapshot = self.buffer().read(cx).snapshot(cx);
10546        for selection in self.selections.all::<usize>(cx) {
10547            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10548        }
10549
10550        let buffer = self.buffer().read(cx);
10551        let ranges = buffer_ids
10552            .into_iter()
10553            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10554            .collect::<Vec<_>>();
10555
10556        self.restore_hunks_in_ranges(ranges, window, cx);
10557    }
10558
10559    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10560        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10561        let selections = self
10562            .selections
10563            .all(cx)
10564            .into_iter()
10565            .map(|s| s.range())
10566            .collect();
10567        self.restore_hunks_in_ranges(selections, window, cx);
10568    }
10569
10570    pub fn restore_hunks_in_ranges(
10571        &mut self,
10572        ranges: Vec<Range<Point>>,
10573        window: &mut Window,
10574        cx: &mut Context<Editor>,
10575    ) {
10576        let mut revert_changes = HashMap::default();
10577        let chunk_by = self
10578            .snapshot(window, cx)
10579            .hunks_for_ranges(ranges)
10580            .into_iter()
10581            .chunk_by(|hunk| hunk.buffer_id);
10582        for (buffer_id, hunks) in &chunk_by {
10583            let hunks = hunks.collect::<Vec<_>>();
10584            for hunk in &hunks {
10585                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10586            }
10587            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10588        }
10589        drop(chunk_by);
10590        if !revert_changes.is_empty() {
10591            self.transact(window, cx, |editor, window, cx| {
10592                editor.restore(revert_changes, window, cx);
10593            });
10594        }
10595    }
10596
10597    pub fn open_active_item_in_terminal(
10598        &mut self,
10599        _: &OpenInTerminal,
10600        window: &mut Window,
10601        cx: &mut Context<Self>,
10602    ) {
10603        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10604            let project_path = buffer.read(cx).project_path(cx)?;
10605            let project = self.project()?.read(cx);
10606            let entry = project.entry_for_path(&project_path, cx)?;
10607            let parent = match &entry.canonical_path {
10608                Some(canonical_path) => canonical_path.to_path_buf(),
10609                None => project.absolute_path(&project_path, cx)?,
10610            }
10611            .parent()?
10612            .to_path_buf();
10613            Some(parent)
10614        }) {
10615            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10616        }
10617    }
10618
10619    fn set_breakpoint_context_menu(
10620        &mut self,
10621        display_row: DisplayRow,
10622        position: Option<Anchor>,
10623        clicked_point: gpui::Point<Pixels>,
10624        window: &mut Window,
10625        cx: &mut Context<Self>,
10626    ) {
10627        let source = self
10628            .buffer
10629            .read(cx)
10630            .snapshot(cx)
10631            .anchor_before(Point::new(display_row.0, 0u32));
10632
10633        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10634
10635        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10636            self,
10637            source,
10638            clicked_point,
10639            context_menu,
10640            window,
10641            cx,
10642        );
10643    }
10644
10645    fn add_edit_breakpoint_block(
10646        &mut self,
10647        anchor: Anchor,
10648        breakpoint: &Breakpoint,
10649        edit_action: BreakpointPromptEditAction,
10650        window: &mut Window,
10651        cx: &mut Context<Self>,
10652    ) {
10653        let weak_editor = cx.weak_entity();
10654        let bp_prompt = cx.new(|cx| {
10655            BreakpointPromptEditor::new(
10656                weak_editor,
10657                anchor,
10658                breakpoint.clone(),
10659                edit_action,
10660                window,
10661                cx,
10662            )
10663        });
10664
10665        let height = bp_prompt.update(cx, |this, cx| {
10666            this.prompt
10667                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10668        });
10669        let cloned_prompt = bp_prompt.clone();
10670        let blocks = vec![BlockProperties {
10671            style: BlockStyle::Sticky,
10672            placement: BlockPlacement::Above(anchor),
10673            height: Some(height),
10674            render: Arc::new(move |cx| {
10675                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10676                cloned_prompt.clone().into_any_element()
10677            }),
10678            priority: 0,
10679        }];
10680
10681        let focus_handle = bp_prompt.focus_handle(cx);
10682        window.focus(&focus_handle);
10683
10684        let block_ids = self.insert_blocks(blocks, None, cx);
10685        bp_prompt.update(cx, |prompt, _| {
10686            prompt.add_block_ids(block_ids);
10687        });
10688    }
10689
10690    pub(crate) fn breakpoint_at_row(
10691        &self,
10692        row: u32,
10693        window: &mut Window,
10694        cx: &mut Context<Self>,
10695    ) -> Option<(Anchor, Breakpoint)> {
10696        let snapshot = self.snapshot(window, cx);
10697        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10698
10699        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10700    }
10701
10702    pub(crate) fn breakpoint_at_anchor(
10703        &self,
10704        breakpoint_position: Anchor,
10705        snapshot: &EditorSnapshot,
10706        cx: &mut Context<Self>,
10707    ) -> Option<(Anchor, Breakpoint)> {
10708        let buffer = self
10709            .buffer
10710            .read(cx)
10711            .buffer_for_anchor(breakpoint_position, cx)?;
10712
10713        let enclosing_excerpt = breakpoint_position.excerpt_id;
10714        let buffer_snapshot = buffer.read(cx).snapshot();
10715
10716        let row = buffer_snapshot
10717            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10718            .row;
10719
10720        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10721        let anchor_end = snapshot
10722            .buffer_snapshot
10723            .anchor_after(Point::new(row, line_len));
10724
10725        self.breakpoint_store
10726            .as_ref()?
10727            .read_with(cx, |breakpoint_store, cx| {
10728                breakpoint_store
10729                    .breakpoints(
10730                        &buffer,
10731                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10732                        &buffer_snapshot,
10733                        cx,
10734                    )
10735                    .next()
10736                    .and_then(|(bp, _)| {
10737                        let breakpoint_row = buffer_snapshot
10738                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10739                            .row;
10740
10741                        if breakpoint_row == row {
10742                            snapshot
10743                                .buffer_snapshot
10744                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10745                                .map(|position| (position, bp.bp.clone()))
10746                        } else {
10747                            None
10748                        }
10749                    })
10750            })
10751    }
10752
10753    pub fn edit_log_breakpoint(
10754        &mut self,
10755        _: &EditLogBreakpoint,
10756        window: &mut Window,
10757        cx: &mut Context<Self>,
10758    ) {
10759        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10760            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10761                message: None,
10762                state: BreakpointState::Enabled,
10763                condition: None,
10764                hit_condition: None,
10765            });
10766
10767            self.add_edit_breakpoint_block(
10768                anchor,
10769                &breakpoint,
10770                BreakpointPromptEditAction::Log,
10771                window,
10772                cx,
10773            );
10774        }
10775    }
10776
10777    fn breakpoints_at_cursors(
10778        &self,
10779        window: &mut Window,
10780        cx: &mut Context<Self>,
10781    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10782        let snapshot = self.snapshot(window, cx);
10783        let cursors = self
10784            .selections
10785            .disjoint_anchors()
10786            .iter()
10787            .map(|selection| {
10788                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10789
10790                let breakpoint_position = self
10791                    .breakpoint_at_row(cursor_position.row, window, cx)
10792                    .map(|bp| bp.0)
10793                    .unwrap_or_else(|| {
10794                        snapshot
10795                            .display_snapshot
10796                            .buffer_snapshot
10797                            .anchor_after(Point::new(cursor_position.row, 0))
10798                    });
10799
10800                let breakpoint = self
10801                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10802                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10803
10804                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10805            })
10806            // 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.
10807            .collect::<HashMap<Anchor, _>>();
10808
10809        cursors.into_iter().collect()
10810    }
10811
10812    pub fn enable_breakpoint(
10813        &mut self,
10814        _: &crate::actions::EnableBreakpoint,
10815        window: &mut Window,
10816        cx: &mut Context<Self>,
10817    ) {
10818        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10819            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10820                continue;
10821            };
10822            self.edit_breakpoint_at_anchor(
10823                anchor,
10824                breakpoint,
10825                BreakpointEditAction::InvertState,
10826                cx,
10827            );
10828        }
10829    }
10830
10831    pub fn disable_breakpoint(
10832        &mut self,
10833        _: &crate::actions::DisableBreakpoint,
10834        window: &mut Window,
10835        cx: &mut Context<Self>,
10836    ) {
10837        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10838            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10839                continue;
10840            };
10841            self.edit_breakpoint_at_anchor(
10842                anchor,
10843                breakpoint,
10844                BreakpointEditAction::InvertState,
10845                cx,
10846            );
10847        }
10848    }
10849
10850    pub fn toggle_breakpoint(
10851        &mut self,
10852        _: &crate::actions::ToggleBreakpoint,
10853        window: &mut Window,
10854        cx: &mut Context<Self>,
10855    ) {
10856        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10857            if let Some(breakpoint) = breakpoint {
10858                self.edit_breakpoint_at_anchor(
10859                    anchor,
10860                    breakpoint,
10861                    BreakpointEditAction::Toggle,
10862                    cx,
10863                );
10864            } else {
10865                self.edit_breakpoint_at_anchor(
10866                    anchor,
10867                    Breakpoint::new_standard(),
10868                    BreakpointEditAction::Toggle,
10869                    cx,
10870                );
10871            }
10872        }
10873    }
10874
10875    pub fn edit_breakpoint_at_anchor(
10876        &mut self,
10877        breakpoint_position: Anchor,
10878        breakpoint: Breakpoint,
10879        edit_action: BreakpointEditAction,
10880        cx: &mut Context<Self>,
10881    ) {
10882        let Some(breakpoint_store) = &self.breakpoint_store else {
10883            return;
10884        };
10885
10886        let Some(buffer) = self
10887            .buffer
10888            .read(cx)
10889            .buffer_for_anchor(breakpoint_position, cx)
10890        else {
10891            return;
10892        };
10893
10894        breakpoint_store.update(cx, |breakpoint_store, cx| {
10895            breakpoint_store.toggle_breakpoint(
10896                buffer,
10897                BreakpointWithPosition {
10898                    position: breakpoint_position.text_anchor,
10899                    bp: breakpoint,
10900                },
10901                edit_action,
10902                cx,
10903            );
10904        });
10905
10906        cx.notify();
10907    }
10908
10909    #[cfg(any(test, feature = "test-support"))]
10910    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10911        self.breakpoint_store.clone()
10912    }
10913
10914    pub fn prepare_restore_change(
10915        &self,
10916        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10917        hunk: &MultiBufferDiffHunk,
10918        cx: &mut App,
10919    ) -> Option<()> {
10920        if hunk.is_created_file() {
10921            return None;
10922        }
10923        let buffer = self.buffer.read(cx);
10924        let diff = buffer.diff_for(hunk.buffer_id)?;
10925        let buffer = buffer.buffer(hunk.buffer_id)?;
10926        let buffer = buffer.read(cx);
10927        let original_text = diff
10928            .read(cx)
10929            .base_text()
10930            .as_rope()
10931            .slice(hunk.diff_base_byte_range.clone());
10932        let buffer_snapshot = buffer.snapshot();
10933        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10934        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10935            probe
10936                .0
10937                .start
10938                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10939                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10940        }) {
10941            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10942            Some(())
10943        } else {
10944            None
10945        }
10946    }
10947
10948    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10949        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10950    }
10951
10952    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10953        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10954    }
10955
10956    fn manipulate_lines<M>(
10957        &mut self,
10958        window: &mut Window,
10959        cx: &mut Context<Self>,
10960        mut manipulate: M,
10961    ) where
10962        M: FnMut(&str) -> LineManipulationResult,
10963    {
10964        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10965
10966        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10967        let buffer = self.buffer.read(cx).snapshot(cx);
10968
10969        let mut edits = Vec::new();
10970
10971        let selections = self.selections.all::<Point>(cx);
10972        let mut selections = selections.iter().peekable();
10973        let mut contiguous_row_selections = Vec::new();
10974        let mut new_selections = Vec::new();
10975        let mut added_lines = 0;
10976        let mut removed_lines = 0;
10977
10978        while let Some(selection) = selections.next() {
10979            let (start_row, end_row) = consume_contiguous_rows(
10980                &mut contiguous_row_selections,
10981                selection,
10982                &display_map,
10983                &mut selections,
10984            );
10985
10986            let start_point = Point::new(start_row.0, 0);
10987            let end_point = Point::new(
10988                end_row.previous_row().0,
10989                buffer.line_len(end_row.previous_row()),
10990            );
10991            let text = buffer
10992                .text_for_range(start_point..end_point)
10993                .collect::<String>();
10994
10995            let LineManipulationResult {
10996                new_text,
10997                line_count_before,
10998                line_count_after,
10999            } = manipulate(&text);
11000
11001            edits.push((start_point..end_point, new_text));
11002
11003            // Selections must change based on added and removed line count
11004            let start_row =
11005                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11006            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11007            new_selections.push(Selection {
11008                id: selection.id,
11009                start: start_row,
11010                end: end_row,
11011                goal: SelectionGoal::None,
11012                reversed: selection.reversed,
11013            });
11014
11015            if line_count_after > line_count_before {
11016                added_lines += line_count_after - line_count_before;
11017            } else if line_count_before > line_count_after {
11018                removed_lines += line_count_before - line_count_after;
11019            }
11020        }
11021
11022        self.transact(window, cx, |this, window, cx| {
11023            let buffer = this.buffer.update(cx, |buffer, cx| {
11024                buffer.edit(edits, None, cx);
11025                buffer.snapshot(cx)
11026            });
11027
11028            // Recalculate offsets on newly edited buffer
11029            let new_selections = new_selections
11030                .iter()
11031                .map(|s| {
11032                    let start_point = Point::new(s.start.0, 0);
11033                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11034                    Selection {
11035                        id: s.id,
11036                        start: buffer.point_to_offset(start_point),
11037                        end: buffer.point_to_offset(end_point),
11038                        goal: s.goal,
11039                        reversed: s.reversed,
11040                    }
11041                })
11042                .collect();
11043
11044            this.change_selections(Default::default(), window, cx, |s| {
11045                s.select(new_selections);
11046            });
11047
11048            this.request_autoscroll(Autoscroll::fit(), cx);
11049        });
11050    }
11051
11052    fn manipulate_immutable_lines<Fn>(
11053        &mut self,
11054        window: &mut Window,
11055        cx: &mut Context<Self>,
11056        mut callback: Fn,
11057    ) where
11058        Fn: FnMut(&mut Vec<&str>),
11059    {
11060        self.manipulate_lines(window, cx, |text| {
11061            let mut lines: Vec<&str> = text.split('\n').collect();
11062            let line_count_before = lines.len();
11063
11064            callback(&mut lines);
11065
11066            LineManipulationResult {
11067                new_text: lines.join("\n"),
11068                line_count_before,
11069                line_count_after: lines.len(),
11070            }
11071        });
11072    }
11073
11074    fn manipulate_mutable_lines<Fn>(
11075        &mut self,
11076        window: &mut Window,
11077        cx: &mut Context<Self>,
11078        mut callback: Fn,
11079    ) where
11080        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11081    {
11082        self.manipulate_lines(window, cx, |text| {
11083            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11084            let line_count_before = lines.len();
11085
11086            callback(&mut lines);
11087
11088            LineManipulationResult {
11089                new_text: lines.join("\n"),
11090                line_count_before,
11091                line_count_after: lines.len(),
11092            }
11093        });
11094    }
11095
11096    pub fn convert_indentation_to_spaces(
11097        &mut self,
11098        _: &ConvertIndentationToSpaces,
11099        window: &mut Window,
11100        cx: &mut Context<Self>,
11101    ) {
11102        let settings = self.buffer.read(cx).language_settings(cx);
11103        let tab_size = settings.tab_size.get() as usize;
11104
11105        self.manipulate_mutable_lines(window, cx, |lines| {
11106            // Allocates a reasonably sized scratch buffer once for the whole loop
11107            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11108            // Avoids recomputing spaces that could be inserted many times
11109            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11110                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11111                .collect();
11112
11113            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11114                let mut chars = line.as_ref().chars();
11115                let mut col = 0;
11116                let mut changed = false;
11117
11118                for ch in chars.by_ref() {
11119                    match ch {
11120                        ' ' => {
11121                            reindented_line.push(' ');
11122                            col += 1;
11123                        }
11124                        '\t' => {
11125                            // \t are converted to spaces depending on the current column
11126                            let spaces_len = tab_size - (col % tab_size);
11127                            reindented_line.extend(&space_cache[spaces_len - 1]);
11128                            col += spaces_len;
11129                            changed = true;
11130                        }
11131                        _ => {
11132                            // If we dont append before break, the character is consumed
11133                            reindented_line.push(ch);
11134                            break;
11135                        }
11136                    }
11137                }
11138
11139                if !changed {
11140                    reindented_line.clear();
11141                    continue;
11142                }
11143                // Append the rest of the line and replace old reference with new one
11144                reindented_line.extend(chars);
11145                *line = Cow::Owned(reindented_line.clone());
11146                reindented_line.clear();
11147            }
11148        });
11149    }
11150
11151    pub fn convert_indentation_to_tabs(
11152        &mut self,
11153        _: &ConvertIndentationToTabs,
11154        window: &mut Window,
11155        cx: &mut Context<Self>,
11156    ) {
11157        let settings = self.buffer.read(cx).language_settings(cx);
11158        let tab_size = settings.tab_size.get() as usize;
11159
11160        self.manipulate_mutable_lines(window, cx, |lines| {
11161            // Allocates a reasonably sized buffer once for the whole loop
11162            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11163            // Avoids recomputing spaces that could be inserted many times
11164            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11165                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11166                .collect();
11167
11168            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11169                let mut chars = line.chars();
11170                let mut spaces_count = 0;
11171                let mut first_non_indent_char = None;
11172                let mut changed = false;
11173
11174                for ch in chars.by_ref() {
11175                    match ch {
11176                        ' ' => {
11177                            // Keep track of spaces. Append \t when we reach tab_size
11178                            spaces_count += 1;
11179                            changed = true;
11180                            if spaces_count == tab_size {
11181                                reindented_line.push('\t');
11182                                spaces_count = 0;
11183                            }
11184                        }
11185                        '\t' => {
11186                            reindented_line.push('\t');
11187                            spaces_count = 0;
11188                        }
11189                        _ => {
11190                            // Dont append it yet, we might have remaining spaces
11191                            first_non_indent_char = Some(ch);
11192                            break;
11193                        }
11194                    }
11195                }
11196
11197                if !changed {
11198                    reindented_line.clear();
11199                    continue;
11200                }
11201                // Remaining spaces that didn't make a full tab stop
11202                if spaces_count > 0 {
11203                    reindented_line.extend(&space_cache[spaces_count - 1]);
11204                }
11205                // If we consume an extra character that was not indentation, add it back
11206                if let Some(extra_char) = first_non_indent_char {
11207                    reindented_line.push(extra_char);
11208                }
11209                // Append the rest of the line and replace old reference with new one
11210                reindented_line.extend(chars);
11211                *line = Cow::Owned(reindented_line.clone());
11212                reindented_line.clear();
11213            }
11214        });
11215    }
11216
11217    pub fn convert_to_upper_case(
11218        &mut self,
11219        _: &ConvertToUpperCase,
11220        window: &mut Window,
11221        cx: &mut Context<Self>,
11222    ) {
11223        self.manipulate_text(window, cx, |text| text.to_uppercase())
11224    }
11225
11226    pub fn convert_to_lower_case(
11227        &mut self,
11228        _: &ConvertToLowerCase,
11229        window: &mut Window,
11230        cx: &mut Context<Self>,
11231    ) {
11232        self.manipulate_text(window, cx, |text| text.to_lowercase())
11233    }
11234
11235    pub fn convert_to_title_case(
11236        &mut self,
11237        _: &ConvertToTitleCase,
11238        window: &mut Window,
11239        cx: &mut Context<Self>,
11240    ) {
11241        self.manipulate_text(window, cx, |text| {
11242            text.split('\n')
11243                .map(|line| line.to_case(Case::Title))
11244                .join("\n")
11245        })
11246    }
11247
11248    pub fn convert_to_snake_case(
11249        &mut self,
11250        _: &ConvertToSnakeCase,
11251        window: &mut Window,
11252        cx: &mut Context<Self>,
11253    ) {
11254        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11255    }
11256
11257    pub fn convert_to_kebab_case(
11258        &mut self,
11259        _: &ConvertToKebabCase,
11260        window: &mut Window,
11261        cx: &mut Context<Self>,
11262    ) {
11263        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11264    }
11265
11266    pub fn convert_to_upper_camel_case(
11267        &mut self,
11268        _: &ConvertToUpperCamelCase,
11269        window: &mut Window,
11270        cx: &mut Context<Self>,
11271    ) {
11272        self.manipulate_text(window, cx, |text| {
11273            text.split('\n')
11274                .map(|line| line.to_case(Case::UpperCamel))
11275                .join("\n")
11276        })
11277    }
11278
11279    pub fn convert_to_lower_camel_case(
11280        &mut self,
11281        _: &ConvertToLowerCamelCase,
11282        window: &mut Window,
11283        cx: &mut Context<Self>,
11284    ) {
11285        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11286    }
11287
11288    pub fn convert_to_opposite_case(
11289        &mut self,
11290        _: &ConvertToOppositeCase,
11291        window: &mut Window,
11292        cx: &mut Context<Self>,
11293    ) {
11294        self.manipulate_text(window, cx, |text| {
11295            text.chars()
11296                .fold(String::with_capacity(text.len()), |mut t, c| {
11297                    if c.is_uppercase() {
11298                        t.extend(c.to_lowercase());
11299                    } else {
11300                        t.extend(c.to_uppercase());
11301                    }
11302                    t
11303                })
11304        })
11305    }
11306
11307    pub fn convert_to_sentence_case(
11308        &mut self,
11309        _: &ConvertToSentenceCase,
11310        window: &mut Window,
11311        cx: &mut Context<Self>,
11312    ) {
11313        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11314    }
11315
11316    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11317        self.manipulate_text(window, cx, |text| {
11318            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11319            if has_upper_case_characters {
11320                text.to_lowercase()
11321            } else {
11322                text.to_uppercase()
11323            }
11324        })
11325    }
11326
11327    pub fn convert_to_rot13(
11328        &mut self,
11329        _: &ConvertToRot13,
11330        window: &mut Window,
11331        cx: &mut Context<Self>,
11332    ) {
11333        self.manipulate_text(window, cx, |text| {
11334            text.chars()
11335                .map(|c| match c {
11336                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11337                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11338                    _ => c,
11339                })
11340                .collect()
11341        })
11342    }
11343
11344    pub fn convert_to_rot47(
11345        &mut self,
11346        _: &ConvertToRot47,
11347        window: &mut Window,
11348        cx: &mut Context<Self>,
11349    ) {
11350        self.manipulate_text(window, cx, |text| {
11351            text.chars()
11352                .map(|c| {
11353                    let code_point = c as u32;
11354                    if code_point >= 33 && code_point <= 126 {
11355                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11356                    }
11357                    c
11358                })
11359                .collect()
11360        })
11361    }
11362
11363    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11364    where
11365        Fn: FnMut(&str) -> String,
11366    {
11367        let buffer = self.buffer.read(cx).snapshot(cx);
11368
11369        let mut new_selections = Vec::new();
11370        let mut edits = Vec::new();
11371        let mut selection_adjustment = 0i32;
11372
11373        for selection in self.selections.all::<usize>(cx) {
11374            let selection_is_empty = selection.is_empty();
11375
11376            let (start, end) = if selection_is_empty {
11377                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11378                (word_range.start, word_range.end)
11379            } else {
11380                (selection.start, selection.end)
11381            };
11382
11383            let text = buffer.text_for_range(start..end).collect::<String>();
11384            let old_length = text.len() as i32;
11385            let text = callback(&text);
11386
11387            new_selections.push(Selection {
11388                start: (start as i32 - selection_adjustment) as usize,
11389                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11390                goal: SelectionGoal::None,
11391                ..selection
11392            });
11393
11394            selection_adjustment += old_length - text.len() as i32;
11395
11396            edits.push((start..end, text));
11397        }
11398
11399        self.transact(window, cx, |this, window, cx| {
11400            this.buffer.update(cx, |buffer, cx| {
11401                buffer.edit(edits, None, cx);
11402            });
11403
11404            this.change_selections(Default::default(), window, cx, |s| {
11405                s.select(new_selections);
11406            });
11407
11408            this.request_autoscroll(Autoscroll::fit(), cx);
11409        });
11410    }
11411
11412    pub fn move_selection_on_drop(
11413        &mut self,
11414        selection: &Selection<Anchor>,
11415        target: DisplayPoint,
11416        is_cut: bool,
11417        window: &mut Window,
11418        cx: &mut Context<Self>,
11419    ) {
11420        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11421        let buffer = &display_map.buffer_snapshot;
11422        let mut edits = Vec::new();
11423        let insert_point = display_map
11424            .clip_point(target, Bias::Left)
11425            .to_point(&display_map);
11426        let text = buffer
11427            .text_for_range(selection.start..selection.end)
11428            .collect::<String>();
11429        if is_cut {
11430            edits.push(((selection.start..selection.end), String::new()));
11431        }
11432        let insert_anchor = buffer.anchor_before(insert_point);
11433        edits.push(((insert_anchor..insert_anchor), text));
11434        let last_edit_start = insert_anchor.bias_left(buffer);
11435        let last_edit_end = insert_anchor.bias_right(buffer);
11436        self.transact(window, cx, |this, window, cx| {
11437            this.buffer.update(cx, |buffer, cx| {
11438                buffer.edit(edits, None, cx);
11439            });
11440            this.change_selections(Default::default(), window, cx, |s| {
11441                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11442            });
11443        });
11444    }
11445
11446    pub fn clear_selection_drag_state(&mut self) {
11447        self.selection_drag_state = SelectionDragState::None;
11448    }
11449
11450    pub fn duplicate(
11451        &mut self,
11452        upwards: bool,
11453        whole_lines: bool,
11454        window: &mut Window,
11455        cx: &mut Context<Self>,
11456    ) {
11457        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11458
11459        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11460        let buffer = &display_map.buffer_snapshot;
11461        let selections = self.selections.all::<Point>(cx);
11462
11463        let mut edits = Vec::new();
11464        let mut selections_iter = selections.iter().peekable();
11465        while let Some(selection) = selections_iter.next() {
11466            let mut rows = selection.spanned_rows(false, &display_map);
11467            // duplicate line-wise
11468            if whole_lines || selection.start == selection.end {
11469                // Avoid duplicating the same lines twice.
11470                while let Some(next_selection) = selections_iter.peek() {
11471                    let next_rows = next_selection.spanned_rows(false, &display_map);
11472                    if next_rows.start < rows.end {
11473                        rows.end = next_rows.end;
11474                        selections_iter.next().unwrap();
11475                    } else {
11476                        break;
11477                    }
11478                }
11479
11480                // Copy the text from the selected row region and splice it either at the start
11481                // or end of the region.
11482                let start = Point::new(rows.start.0, 0);
11483                let end = Point::new(
11484                    rows.end.previous_row().0,
11485                    buffer.line_len(rows.end.previous_row()),
11486                );
11487                let text = buffer
11488                    .text_for_range(start..end)
11489                    .chain(Some("\n"))
11490                    .collect::<String>();
11491                let insert_location = if upwards {
11492                    Point::new(rows.end.0, 0)
11493                } else {
11494                    start
11495                };
11496                edits.push((insert_location..insert_location, text));
11497            } else {
11498                // duplicate character-wise
11499                let start = selection.start;
11500                let end = selection.end;
11501                let text = buffer.text_for_range(start..end).collect::<String>();
11502                edits.push((selection.end..selection.end, text));
11503            }
11504        }
11505
11506        self.transact(window, cx, |this, _, cx| {
11507            this.buffer.update(cx, |buffer, cx| {
11508                buffer.edit(edits, None, cx);
11509            });
11510
11511            this.request_autoscroll(Autoscroll::fit(), cx);
11512        });
11513    }
11514
11515    pub fn duplicate_line_up(
11516        &mut self,
11517        _: &DuplicateLineUp,
11518        window: &mut Window,
11519        cx: &mut Context<Self>,
11520    ) {
11521        self.duplicate(true, true, window, cx);
11522    }
11523
11524    pub fn duplicate_line_down(
11525        &mut self,
11526        _: &DuplicateLineDown,
11527        window: &mut Window,
11528        cx: &mut Context<Self>,
11529    ) {
11530        self.duplicate(false, true, window, cx);
11531    }
11532
11533    pub fn duplicate_selection(
11534        &mut self,
11535        _: &DuplicateSelection,
11536        window: &mut Window,
11537        cx: &mut Context<Self>,
11538    ) {
11539        self.duplicate(false, false, window, cx);
11540    }
11541
11542    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11543        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11544        if self.mode.is_single_line() {
11545            cx.propagate();
11546            return;
11547        }
11548
11549        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11550        let buffer = self.buffer.read(cx).snapshot(cx);
11551
11552        let mut edits = Vec::new();
11553        let mut unfold_ranges = Vec::new();
11554        let mut refold_creases = Vec::new();
11555
11556        let selections = self.selections.all::<Point>(cx);
11557        let mut selections = selections.iter().peekable();
11558        let mut contiguous_row_selections = Vec::new();
11559        let mut new_selections = Vec::new();
11560
11561        while let Some(selection) = selections.next() {
11562            // Find all the selections that span a contiguous row range
11563            let (start_row, end_row) = consume_contiguous_rows(
11564                &mut contiguous_row_selections,
11565                selection,
11566                &display_map,
11567                &mut selections,
11568            );
11569
11570            // Move the text spanned by the row range to be before the line preceding the row range
11571            if start_row.0 > 0 {
11572                let range_to_move = Point::new(
11573                    start_row.previous_row().0,
11574                    buffer.line_len(start_row.previous_row()),
11575                )
11576                    ..Point::new(
11577                        end_row.previous_row().0,
11578                        buffer.line_len(end_row.previous_row()),
11579                    );
11580                let insertion_point = display_map
11581                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11582                    .0;
11583
11584                // Don't move lines across excerpts
11585                if buffer
11586                    .excerpt_containing(insertion_point..range_to_move.end)
11587                    .is_some()
11588                {
11589                    let text = buffer
11590                        .text_for_range(range_to_move.clone())
11591                        .flat_map(|s| s.chars())
11592                        .skip(1)
11593                        .chain(['\n'])
11594                        .collect::<String>();
11595
11596                    edits.push((
11597                        buffer.anchor_after(range_to_move.start)
11598                            ..buffer.anchor_before(range_to_move.end),
11599                        String::new(),
11600                    ));
11601                    let insertion_anchor = buffer.anchor_after(insertion_point);
11602                    edits.push((insertion_anchor..insertion_anchor, text));
11603
11604                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11605
11606                    // Move selections up
11607                    new_selections.extend(contiguous_row_selections.drain(..).map(
11608                        |mut selection| {
11609                            selection.start.row -= row_delta;
11610                            selection.end.row -= row_delta;
11611                            selection
11612                        },
11613                    ));
11614
11615                    // Move folds up
11616                    unfold_ranges.push(range_to_move.clone());
11617                    for fold in display_map.folds_in_range(
11618                        buffer.anchor_before(range_to_move.start)
11619                            ..buffer.anchor_after(range_to_move.end),
11620                    ) {
11621                        let mut start = fold.range.start.to_point(&buffer);
11622                        let mut end = fold.range.end.to_point(&buffer);
11623                        start.row -= row_delta;
11624                        end.row -= row_delta;
11625                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11626                    }
11627                }
11628            }
11629
11630            // If we didn't move line(s), preserve the existing selections
11631            new_selections.append(&mut contiguous_row_selections);
11632        }
11633
11634        self.transact(window, cx, |this, window, cx| {
11635            this.unfold_ranges(&unfold_ranges, true, true, cx);
11636            this.buffer.update(cx, |buffer, cx| {
11637                for (range, text) in edits {
11638                    buffer.edit([(range, text)], None, cx);
11639                }
11640            });
11641            this.fold_creases(refold_creases, true, window, cx);
11642            this.change_selections(Default::default(), window, cx, |s| {
11643                s.select(new_selections);
11644            })
11645        });
11646    }
11647
11648    pub fn move_line_down(
11649        &mut self,
11650        _: &MoveLineDown,
11651        window: &mut Window,
11652        cx: &mut Context<Self>,
11653    ) {
11654        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11655        if self.mode.is_single_line() {
11656            cx.propagate();
11657            return;
11658        }
11659
11660        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11661        let buffer = self.buffer.read(cx).snapshot(cx);
11662
11663        let mut edits = Vec::new();
11664        let mut unfold_ranges = Vec::new();
11665        let mut refold_creases = Vec::new();
11666
11667        let selections = self.selections.all::<Point>(cx);
11668        let mut selections = selections.iter().peekable();
11669        let mut contiguous_row_selections = Vec::new();
11670        let mut new_selections = Vec::new();
11671
11672        while let Some(selection) = selections.next() {
11673            // Find all the selections that span a contiguous row range
11674            let (start_row, end_row) = consume_contiguous_rows(
11675                &mut contiguous_row_selections,
11676                selection,
11677                &display_map,
11678                &mut selections,
11679            );
11680
11681            // Move the text spanned by the row range to be after the last line of the row range
11682            if end_row.0 <= buffer.max_point().row {
11683                let range_to_move =
11684                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11685                let insertion_point = display_map
11686                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11687                    .0;
11688
11689                // Don't move lines across excerpt boundaries
11690                if buffer
11691                    .excerpt_containing(range_to_move.start..insertion_point)
11692                    .is_some()
11693                {
11694                    let mut text = String::from("\n");
11695                    text.extend(buffer.text_for_range(range_to_move.clone()));
11696                    text.pop(); // Drop trailing newline
11697                    edits.push((
11698                        buffer.anchor_after(range_to_move.start)
11699                            ..buffer.anchor_before(range_to_move.end),
11700                        String::new(),
11701                    ));
11702                    let insertion_anchor = buffer.anchor_after(insertion_point);
11703                    edits.push((insertion_anchor..insertion_anchor, text));
11704
11705                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11706
11707                    // Move selections down
11708                    new_selections.extend(contiguous_row_selections.drain(..).map(
11709                        |mut selection| {
11710                            selection.start.row += row_delta;
11711                            selection.end.row += row_delta;
11712                            selection
11713                        },
11714                    ));
11715
11716                    // Move folds down
11717                    unfold_ranges.push(range_to_move.clone());
11718                    for fold in display_map.folds_in_range(
11719                        buffer.anchor_before(range_to_move.start)
11720                            ..buffer.anchor_after(range_to_move.end),
11721                    ) {
11722                        let mut start = fold.range.start.to_point(&buffer);
11723                        let mut end = fold.range.end.to_point(&buffer);
11724                        start.row += row_delta;
11725                        end.row += row_delta;
11726                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11727                    }
11728                }
11729            }
11730
11731            // If we didn't move line(s), preserve the existing selections
11732            new_selections.append(&mut contiguous_row_selections);
11733        }
11734
11735        self.transact(window, cx, |this, window, cx| {
11736            this.unfold_ranges(&unfold_ranges, true, true, cx);
11737            this.buffer.update(cx, |buffer, cx| {
11738                for (range, text) in edits {
11739                    buffer.edit([(range, text)], None, cx);
11740                }
11741            });
11742            this.fold_creases(refold_creases, true, window, cx);
11743            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11744        });
11745    }
11746
11747    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11748        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11749        let text_layout_details = &self.text_layout_details(window);
11750        self.transact(window, cx, |this, window, cx| {
11751            let edits = this.change_selections(Default::default(), window, cx, |s| {
11752                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11753                s.move_with(|display_map, selection| {
11754                    if !selection.is_empty() {
11755                        return;
11756                    }
11757
11758                    let mut head = selection.head();
11759                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11760                    if head.column() == display_map.line_len(head.row()) {
11761                        transpose_offset = display_map
11762                            .buffer_snapshot
11763                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11764                    }
11765
11766                    if transpose_offset == 0 {
11767                        return;
11768                    }
11769
11770                    *head.column_mut() += 1;
11771                    head = display_map.clip_point(head, Bias::Right);
11772                    let goal = SelectionGoal::HorizontalPosition(
11773                        display_map
11774                            .x_for_display_point(head, text_layout_details)
11775                            .into(),
11776                    );
11777                    selection.collapse_to(head, goal);
11778
11779                    let transpose_start = display_map
11780                        .buffer_snapshot
11781                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11782                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11783                        let transpose_end = display_map
11784                            .buffer_snapshot
11785                            .clip_offset(transpose_offset + 1, Bias::Right);
11786                        if let Some(ch) =
11787                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11788                        {
11789                            edits.push((transpose_start..transpose_offset, String::new()));
11790                            edits.push((transpose_end..transpose_end, ch.to_string()));
11791                        }
11792                    }
11793                });
11794                edits
11795            });
11796            this.buffer
11797                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11798            let selections = this.selections.all::<usize>(cx);
11799            this.change_selections(Default::default(), window, cx, |s| {
11800                s.select(selections);
11801            });
11802        });
11803    }
11804
11805    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11806        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11807        if self.mode.is_single_line() {
11808            cx.propagate();
11809            return;
11810        }
11811
11812        self.rewrap_impl(RewrapOptions::default(), cx)
11813    }
11814
11815    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11816        let buffer = self.buffer.read(cx).snapshot(cx);
11817        let selections = self.selections.all::<Point>(cx);
11818
11819        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11820        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11821            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11822                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11823                .peekable();
11824
11825            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11826                row
11827            } else {
11828                return Vec::new();
11829            };
11830
11831            let language_settings = buffer.language_settings_at(selection.head(), cx);
11832            let language_scope = buffer.language_scope_at(selection.head());
11833
11834            let indent_and_prefix_for_row =
11835                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11836                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11837                    let (comment_prefix, rewrap_prefix) =
11838                        if let Some(language_scope) = &language_scope {
11839                            let indent_end = Point::new(row, indent.len);
11840                            let comment_prefix = language_scope
11841                                .line_comment_prefixes()
11842                                .iter()
11843                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11844                                .map(|prefix| prefix.to_string());
11845                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11846                            let line_text_after_indent = buffer
11847                                .text_for_range(indent_end..line_end)
11848                                .collect::<String>();
11849                            let rewrap_prefix = language_scope
11850                                .rewrap_prefixes()
11851                                .iter()
11852                                .find_map(|prefix_regex| {
11853                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11854                                        if mat.start() == 0 {
11855                                            Some(mat.as_str().to_string())
11856                                        } else {
11857                                            None
11858                                        }
11859                                    })
11860                                })
11861                                .flatten();
11862                            (comment_prefix, rewrap_prefix)
11863                        } else {
11864                            (None, None)
11865                        };
11866                    (indent, comment_prefix, rewrap_prefix)
11867                };
11868
11869            let mut ranges = Vec::new();
11870            let from_empty_selection = selection.is_empty();
11871
11872            let mut current_range_start = first_row;
11873            let mut prev_row = first_row;
11874            let (
11875                mut current_range_indent,
11876                mut current_range_comment_prefix,
11877                mut current_range_rewrap_prefix,
11878            ) = indent_and_prefix_for_row(first_row);
11879
11880            for row in non_blank_rows_iter.skip(1) {
11881                let has_paragraph_break = row > prev_row + 1;
11882
11883                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11884                    indent_and_prefix_for_row(row);
11885
11886                let has_indent_change = row_indent != current_range_indent;
11887                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11888
11889                let has_boundary_change = has_comment_change
11890                    || row_rewrap_prefix.is_some()
11891                    || (has_indent_change && current_range_comment_prefix.is_some());
11892
11893                if has_paragraph_break || has_boundary_change {
11894                    ranges.push((
11895                        language_settings.clone(),
11896                        Point::new(current_range_start, 0)
11897                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11898                        current_range_indent,
11899                        current_range_comment_prefix.clone(),
11900                        current_range_rewrap_prefix.clone(),
11901                        from_empty_selection,
11902                    ));
11903                    current_range_start = row;
11904                    current_range_indent = row_indent;
11905                    current_range_comment_prefix = row_comment_prefix;
11906                    current_range_rewrap_prefix = row_rewrap_prefix;
11907                }
11908                prev_row = row;
11909            }
11910
11911            ranges.push((
11912                language_settings.clone(),
11913                Point::new(current_range_start, 0)
11914                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11915                current_range_indent,
11916                current_range_comment_prefix,
11917                current_range_rewrap_prefix,
11918                from_empty_selection,
11919            ));
11920
11921            ranges
11922        });
11923
11924        let mut edits = Vec::new();
11925        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11926
11927        for (
11928            language_settings,
11929            wrap_range,
11930            indent_size,
11931            comment_prefix,
11932            rewrap_prefix,
11933            from_empty_selection,
11934        ) in wrap_ranges
11935        {
11936            let mut start_row = wrap_range.start.row;
11937            let mut end_row = wrap_range.end.row;
11938
11939            // Skip selections that overlap with a range that has already been rewrapped.
11940            let selection_range = start_row..end_row;
11941            if rewrapped_row_ranges
11942                .iter()
11943                .any(|range| range.overlaps(&selection_range))
11944            {
11945                continue;
11946            }
11947
11948            let tab_size = language_settings.tab_size;
11949
11950            let indent_prefix = indent_size.chars().collect::<String>();
11951            let mut line_prefix = indent_prefix.clone();
11952            let mut inside_comment = false;
11953            if let Some(prefix) = &comment_prefix {
11954                line_prefix.push_str(prefix);
11955                inside_comment = true;
11956            }
11957            if let Some(prefix) = &rewrap_prefix {
11958                line_prefix.push_str(prefix);
11959            }
11960
11961            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11962                RewrapBehavior::InComments => inside_comment,
11963                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11964                RewrapBehavior::Anywhere => true,
11965            };
11966
11967            let should_rewrap = options.override_language_settings
11968                || allow_rewrap_based_on_language
11969                || self.hard_wrap.is_some();
11970            if !should_rewrap {
11971                continue;
11972            }
11973
11974            if from_empty_selection {
11975                'expand_upwards: while start_row > 0 {
11976                    let prev_row = start_row - 1;
11977                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11978                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11979                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11980                    {
11981                        start_row = prev_row;
11982                    } else {
11983                        break 'expand_upwards;
11984                    }
11985                }
11986
11987                'expand_downwards: while end_row < buffer.max_point().row {
11988                    let next_row = end_row + 1;
11989                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11990                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11991                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11992                    {
11993                        end_row = next_row;
11994                    } else {
11995                        break 'expand_downwards;
11996                    }
11997                }
11998            }
11999
12000            let start = Point::new(start_row, 0);
12001            let start_offset = start.to_offset(&buffer);
12002            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12003            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12004            let Some(lines_without_prefixes) = selection_text
12005                .lines()
12006                .enumerate()
12007                .map(|(ix, line)| {
12008                    let line_trimmed = line.trim_start();
12009                    if rewrap_prefix.is_some() && ix > 0 {
12010                        Ok(line_trimmed)
12011                    } else {
12012                        line_trimmed
12013                            .strip_prefix(&line_prefix.trim_start())
12014                            .with_context(|| {
12015                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12016                            })
12017                    }
12018                })
12019                .collect::<Result<Vec<_>, _>>()
12020                .log_err()
12021            else {
12022                continue;
12023            };
12024
12025            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12026                buffer
12027                    .language_settings_at(Point::new(start_row, 0), cx)
12028                    .preferred_line_length as usize
12029            });
12030
12031            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12032                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12033            } else {
12034                line_prefix.clone()
12035            };
12036
12037            let wrapped_text = wrap_with_prefix(
12038                line_prefix,
12039                subsequent_lines_prefix,
12040                lines_without_prefixes.join("\n"),
12041                wrap_column,
12042                tab_size,
12043                options.preserve_existing_whitespace,
12044            );
12045
12046            // TODO: should always use char-based diff while still supporting cursor behavior that
12047            // matches vim.
12048            let mut diff_options = DiffOptions::default();
12049            if options.override_language_settings {
12050                diff_options.max_word_diff_len = 0;
12051                diff_options.max_word_diff_line_count = 0;
12052            } else {
12053                diff_options.max_word_diff_len = usize::MAX;
12054                diff_options.max_word_diff_line_count = usize::MAX;
12055            }
12056
12057            for (old_range, new_text) in
12058                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12059            {
12060                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12061                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12062                edits.push((edit_start..edit_end, new_text));
12063            }
12064
12065            rewrapped_row_ranges.push(start_row..=end_row);
12066        }
12067
12068        self.buffer
12069            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12070    }
12071
12072    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
12073        let mut text = String::new();
12074        let buffer = self.buffer.read(cx).snapshot(cx);
12075        let mut selections = self.selections.all::<Point>(cx);
12076        let mut clipboard_selections = Vec::with_capacity(selections.len());
12077        {
12078            let max_point = buffer.max_point();
12079            let mut is_first = true;
12080            for selection in &mut selections {
12081                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12082                if is_entire_line {
12083                    selection.start = Point::new(selection.start.row, 0);
12084                    if !selection.is_empty() && selection.end.column == 0 {
12085                        selection.end = cmp::min(max_point, selection.end);
12086                    } else {
12087                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12088                    }
12089                    selection.goal = SelectionGoal::None;
12090                }
12091                if is_first {
12092                    is_first = false;
12093                } else {
12094                    text += "\n";
12095                }
12096                let mut len = 0;
12097                for chunk in buffer.text_for_range(selection.start..selection.end) {
12098                    text.push_str(chunk);
12099                    len += chunk.len();
12100                }
12101                clipboard_selections.push(ClipboardSelection {
12102                    len,
12103                    is_entire_line,
12104                    first_line_indent: buffer
12105                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12106                        .len,
12107                });
12108            }
12109        }
12110
12111        self.transact(window, cx, |this, window, cx| {
12112            this.change_selections(Default::default(), window, cx, |s| {
12113                s.select(selections);
12114            });
12115            this.insert("", window, cx);
12116        });
12117        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12118    }
12119
12120    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12121        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12122        let item = self.cut_common(window, cx);
12123        cx.write_to_clipboard(item);
12124    }
12125
12126    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12127        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12128        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12129            s.move_with(|snapshot, sel| {
12130                if sel.is_empty() {
12131                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12132                }
12133            });
12134        });
12135        let item = self.cut_common(window, cx);
12136        cx.set_global(KillRing(item))
12137    }
12138
12139    pub fn kill_ring_yank(
12140        &mut self,
12141        _: &KillRingYank,
12142        window: &mut Window,
12143        cx: &mut Context<Self>,
12144    ) {
12145        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12146        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12147            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12148                (kill_ring.text().to_string(), kill_ring.metadata_json())
12149            } else {
12150                return;
12151            }
12152        } else {
12153            return;
12154        };
12155        self.do_paste(&text, metadata, false, window, cx);
12156    }
12157
12158    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12159        self.do_copy(true, cx);
12160    }
12161
12162    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12163        self.do_copy(false, cx);
12164    }
12165
12166    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12167        let selections = self.selections.all::<Point>(cx);
12168        let buffer = self.buffer.read(cx).read(cx);
12169        let mut text = String::new();
12170
12171        let mut clipboard_selections = Vec::with_capacity(selections.len());
12172        {
12173            let max_point = buffer.max_point();
12174            let mut is_first = true;
12175            for selection in &selections {
12176                let mut start = selection.start;
12177                let mut end = selection.end;
12178                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12179                if is_entire_line {
12180                    start = Point::new(start.row, 0);
12181                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12182                }
12183
12184                let mut trimmed_selections = Vec::new();
12185                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12186                    let row = MultiBufferRow(start.row);
12187                    let first_indent = buffer.indent_size_for_line(row);
12188                    if first_indent.len == 0 || start.column > first_indent.len {
12189                        trimmed_selections.push(start..end);
12190                    } else {
12191                        trimmed_selections.push(
12192                            Point::new(row.0, first_indent.len)
12193                                ..Point::new(row.0, buffer.line_len(row)),
12194                        );
12195                        for row in start.row + 1..=end.row {
12196                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12197                            if row == end.row {
12198                                line_len = end.column;
12199                            }
12200                            if line_len == 0 {
12201                                trimmed_selections
12202                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12203                                continue;
12204                            }
12205                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12206                            if row_indent_size.len >= first_indent.len {
12207                                trimmed_selections.push(
12208                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12209                                );
12210                            } else {
12211                                trimmed_selections.clear();
12212                                trimmed_selections.push(start..end);
12213                                break;
12214                            }
12215                        }
12216                    }
12217                } else {
12218                    trimmed_selections.push(start..end);
12219                }
12220
12221                for trimmed_range in trimmed_selections {
12222                    if is_first {
12223                        is_first = false;
12224                    } else {
12225                        text += "\n";
12226                    }
12227                    let mut len = 0;
12228                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12229                        text.push_str(chunk);
12230                        len += chunk.len();
12231                    }
12232                    clipboard_selections.push(ClipboardSelection {
12233                        len,
12234                        is_entire_line,
12235                        first_line_indent: buffer
12236                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12237                            .len,
12238                    });
12239                }
12240            }
12241        }
12242
12243        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12244            text,
12245            clipboard_selections,
12246        ));
12247    }
12248
12249    pub fn do_paste(
12250        &mut self,
12251        text: &String,
12252        clipboard_selections: Option<Vec<ClipboardSelection>>,
12253        handle_entire_lines: bool,
12254        window: &mut Window,
12255        cx: &mut Context<Self>,
12256    ) {
12257        if self.read_only(cx) {
12258            return;
12259        }
12260
12261        let clipboard_text = Cow::Borrowed(text);
12262
12263        self.transact(window, cx, |this, window, cx| {
12264            let had_active_edit_prediction = this.has_active_edit_prediction();
12265
12266            if let Some(mut clipboard_selections) = clipboard_selections {
12267                let old_selections = this.selections.all::<usize>(cx);
12268                let all_selections_were_entire_line =
12269                    clipboard_selections.iter().all(|s| s.is_entire_line);
12270                let first_selection_indent_column =
12271                    clipboard_selections.first().map(|s| s.first_line_indent);
12272                if clipboard_selections.len() != old_selections.len() {
12273                    clipboard_selections.drain(..);
12274                }
12275                let cursor_offset = this.selections.last::<usize>(cx).head();
12276                let mut auto_indent_on_paste = true;
12277
12278                this.buffer.update(cx, |buffer, cx| {
12279                    let snapshot = buffer.read(cx);
12280                    auto_indent_on_paste = snapshot
12281                        .language_settings_at(cursor_offset, cx)
12282                        .auto_indent_on_paste;
12283
12284                    let mut start_offset = 0;
12285                    let mut edits = Vec::new();
12286                    let mut original_indent_columns = Vec::new();
12287                    for (ix, selection) in old_selections.iter().enumerate() {
12288                        let to_insert;
12289                        let entire_line;
12290                        let original_indent_column;
12291                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12292                            let end_offset = start_offset + clipboard_selection.len;
12293                            to_insert = &clipboard_text[start_offset..end_offset];
12294                            entire_line = clipboard_selection.is_entire_line;
12295                            start_offset = end_offset + 1;
12296                            original_indent_column = Some(clipboard_selection.first_line_indent);
12297                        } else {
12298                            to_insert = clipboard_text.as_str();
12299                            entire_line = all_selections_were_entire_line;
12300                            original_indent_column = first_selection_indent_column
12301                        }
12302
12303                        // If the corresponding selection was empty when this slice of the
12304                        // clipboard text was written, then the entire line containing the
12305                        // selection was copied. If this selection is also currently empty,
12306                        // then paste the line before the current line of the buffer.
12307                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12308                            let column = selection.start.to_point(&snapshot).column as usize;
12309                            let line_start = selection.start - column;
12310                            line_start..line_start
12311                        } else {
12312                            selection.range()
12313                        };
12314
12315                        edits.push((range, to_insert));
12316                        original_indent_columns.push(original_indent_column);
12317                    }
12318                    drop(snapshot);
12319
12320                    buffer.edit(
12321                        edits,
12322                        if auto_indent_on_paste {
12323                            Some(AutoindentMode::Block {
12324                                original_indent_columns,
12325                            })
12326                        } else {
12327                            None
12328                        },
12329                        cx,
12330                    );
12331                });
12332
12333                let selections = this.selections.all::<usize>(cx);
12334                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12335            } else {
12336                this.insert(&clipboard_text, window, cx);
12337            }
12338
12339            let trigger_in_words =
12340                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12341
12342            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12343        });
12344    }
12345
12346    pub fn diff_clipboard_with_selection(
12347        &mut self,
12348        _: &DiffClipboardWithSelection,
12349        window: &mut Window,
12350        cx: &mut Context<Self>,
12351    ) {
12352        let selections = self.selections.all::<usize>(cx);
12353
12354        if selections.is_empty() {
12355            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12356            return;
12357        };
12358
12359        let clipboard_text = match cx.read_from_clipboard() {
12360            Some(item) => match item.entries().first() {
12361                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12362                _ => None,
12363            },
12364            None => None,
12365        };
12366
12367        let Some(clipboard_text) = clipboard_text else {
12368            log::warn!("Clipboard doesn't contain text.");
12369            return;
12370        };
12371
12372        window.dispatch_action(
12373            Box::new(DiffClipboardWithSelectionData {
12374                clipboard_text,
12375                editor: cx.entity(),
12376            }),
12377            cx,
12378        );
12379    }
12380
12381    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12382        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12383        if let Some(item) = cx.read_from_clipboard() {
12384            let entries = item.entries();
12385
12386            match entries.first() {
12387                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12388                // of all the pasted entries.
12389                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12390                    .do_paste(
12391                        clipboard_string.text(),
12392                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12393                        true,
12394                        window,
12395                        cx,
12396                    ),
12397                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12398            }
12399        }
12400    }
12401
12402    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12403        if self.read_only(cx) {
12404            return;
12405        }
12406
12407        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12408
12409        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12410            if let Some((selections, _)) =
12411                self.selection_history.transaction(transaction_id).cloned()
12412            {
12413                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12414                    s.select_anchors(selections.to_vec());
12415                });
12416            } else {
12417                log::error!(
12418                    "No entry in selection_history found for undo. \
12419                     This may correspond to a bug where undo does not update the selection. \
12420                     If this is occurring, please add details to \
12421                     https://github.com/zed-industries/zed/issues/22692"
12422                );
12423            }
12424            self.request_autoscroll(Autoscroll::fit(), cx);
12425            self.unmark_text(window, cx);
12426            self.refresh_edit_prediction(true, false, window, cx);
12427            cx.emit(EditorEvent::Edited { transaction_id });
12428            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12429        }
12430    }
12431
12432    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12433        if self.read_only(cx) {
12434            return;
12435        }
12436
12437        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12438
12439        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12440            if let Some((_, Some(selections))) =
12441                self.selection_history.transaction(transaction_id).cloned()
12442            {
12443                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12444                    s.select_anchors(selections.to_vec());
12445                });
12446            } else {
12447                log::error!(
12448                    "No entry in selection_history found for redo. \
12449                     This may correspond to a bug where undo does not update the selection. \
12450                     If this is occurring, please add details to \
12451                     https://github.com/zed-industries/zed/issues/22692"
12452                );
12453            }
12454            self.request_autoscroll(Autoscroll::fit(), cx);
12455            self.unmark_text(window, cx);
12456            self.refresh_edit_prediction(true, false, window, cx);
12457            cx.emit(EditorEvent::Edited { transaction_id });
12458        }
12459    }
12460
12461    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12462        self.buffer
12463            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12464    }
12465
12466    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12467        self.buffer
12468            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12469    }
12470
12471    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12472        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12473        self.change_selections(Default::default(), window, cx, |s| {
12474            s.move_with(|map, selection| {
12475                let cursor = if selection.is_empty() {
12476                    movement::left(map, selection.start)
12477                } else {
12478                    selection.start
12479                };
12480                selection.collapse_to(cursor, SelectionGoal::None);
12481            });
12482        })
12483    }
12484
12485    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12486        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12487        self.change_selections(Default::default(), window, cx, |s| {
12488            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12489        })
12490    }
12491
12492    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12493        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12494        self.change_selections(Default::default(), window, cx, |s| {
12495            s.move_with(|map, selection| {
12496                let cursor = if selection.is_empty() {
12497                    movement::right(map, selection.end)
12498                } else {
12499                    selection.end
12500                };
12501                selection.collapse_to(cursor, SelectionGoal::None)
12502            });
12503        })
12504    }
12505
12506    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12507        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12508        self.change_selections(Default::default(), window, cx, |s| {
12509            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12510        })
12511    }
12512
12513    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12514        if self.take_rename(true, window, cx).is_some() {
12515            return;
12516        }
12517
12518        if self.mode.is_single_line() {
12519            cx.propagate();
12520            return;
12521        }
12522
12523        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12524
12525        let text_layout_details = &self.text_layout_details(window);
12526        let selection_count = self.selections.count();
12527        let first_selection = self.selections.first_anchor();
12528
12529        self.change_selections(Default::default(), window, cx, |s| {
12530            s.move_with(|map, selection| {
12531                if !selection.is_empty() {
12532                    selection.goal = SelectionGoal::None;
12533                }
12534                let (cursor, goal) = movement::up(
12535                    map,
12536                    selection.start,
12537                    selection.goal,
12538                    false,
12539                    text_layout_details,
12540                );
12541                selection.collapse_to(cursor, goal);
12542            });
12543        });
12544
12545        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12546        {
12547            cx.propagate();
12548        }
12549    }
12550
12551    pub fn move_up_by_lines(
12552        &mut self,
12553        action: &MoveUpByLines,
12554        window: &mut Window,
12555        cx: &mut Context<Self>,
12556    ) {
12557        if self.take_rename(true, window, cx).is_some() {
12558            return;
12559        }
12560
12561        if self.mode.is_single_line() {
12562            cx.propagate();
12563            return;
12564        }
12565
12566        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12567
12568        let text_layout_details = &self.text_layout_details(window);
12569
12570        self.change_selections(Default::default(), window, cx, |s| {
12571            s.move_with(|map, selection| {
12572                if !selection.is_empty() {
12573                    selection.goal = SelectionGoal::None;
12574                }
12575                let (cursor, goal) = movement::up_by_rows(
12576                    map,
12577                    selection.start,
12578                    action.lines,
12579                    selection.goal,
12580                    false,
12581                    text_layout_details,
12582                );
12583                selection.collapse_to(cursor, goal);
12584            });
12585        })
12586    }
12587
12588    pub fn move_down_by_lines(
12589        &mut self,
12590        action: &MoveDownByLines,
12591        window: &mut Window,
12592        cx: &mut Context<Self>,
12593    ) {
12594        if self.take_rename(true, window, cx).is_some() {
12595            return;
12596        }
12597
12598        if self.mode.is_single_line() {
12599            cx.propagate();
12600            return;
12601        }
12602
12603        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12604
12605        let text_layout_details = &self.text_layout_details(window);
12606
12607        self.change_selections(Default::default(), window, cx, |s| {
12608            s.move_with(|map, selection| {
12609                if !selection.is_empty() {
12610                    selection.goal = SelectionGoal::None;
12611                }
12612                let (cursor, goal) = movement::down_by_rows(
12613                    map,
12614                    selection.start,
12615                    action.lines,
12616                    selection.goal,
12617                    false,
12618                    text_layout_details,
12619                );
12620                selection.collapse_to(cursor, goal);
12621            });
12622        })
12623    }
12624
12625    pub fn select_down_by_lines(
12626        &mut self,
12627        action: &SelectDownByLines,
12628        window: &mut Window,
12629        cx: &mut Context<Self>,
12630    ) {
12631        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12632        let text_layout_details = &self.text_layout_details(window);
12633        self.change_selections(Default::default(), window, cx, |s| {
12634            s.move_heads_with(|map, head, goal| {
12635                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12636            })
12637        })
12638    }
12639
12640    pub fn select_up_by_lines(
12641        &mut self,
12642        action: &SelectUpByLines,
12643        window: &mut Window,
12644        cx: &mut Context<Self>,
12645    ) {
12646        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12647        let text_layout_details = &self.text_layout_details(window);
12648        self.change_selections(Default::default(), window, cx, |s| {
12649            s.move_heads_with(|map, head, goal| {
12650                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12651            })
12652        })
12653    }
12654
12655    pub fn select_page_up(
12656        &mut self,
12657        _: &SelectPageUp,
12658        window: &mut Window,
12659        cx: &mut Context<Self>,
12660    ) {
12661        let Some(row_count) = self.visible_row_count() else {
12662            return;
12663        };
12664
12665        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12666
12667        let text_layout_details = &self.text_layout_details(window);
12668
12669        self.change_selections(Default::default(), window, cx, |s| {
12670            s.move_heads_with(|map, head, goal| {
12671                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12672            })
12673        })
12674    }
12675
12676    pub fn move_page_up(
12677        &mut self,
12678        action: &MovePageUp,
12679        window: &mut Window,
12680        cx: &mut Context<Self>,
12681    ) {
12682        if self.take_rename(true, window, cx).is_some() {
12683            return;
12684        }
12685
12686        if self
12687            .context_menu
12688            .borrow_mut()
12689            .as_mut()
12690            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12691            .unwrap_or(false)
12692        {
12693            return;
12694        }
12695
12696        if matches!(self.mode, EditorMode::SingleLine) {
12697            cx.propagate();
12698            return;
12699        }
12700
12701        let Some(row_count) = self.visible_row_count() else {
12702            return;
12703        };
12704
12705        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12706
12707        let effects = if action.center_cursor {
12708            SelectionEffects::scroll(Autoscroll::center())
12709        } else {
12710            SelectionEffects::default()
12711        };
12712
12713        let text_layout_details = &self.text_layout_details(window);
12714
12715        self.change_selections(effects, window, cx, |s| {
12716            s.move_with(|map, selection| {
12717                if !selection.is_empty() {
12718                    selection.goal = SelectionGoal::None;
12719                }
12720                let (cursor, goal) = movement::up_by_rows(
12721                    map,
12722                    selection.end,
12723                    row_count,
12724                    selection.goal,
12725                    false,
12726                    text_layout_details,
12727                );
12728                selection.collapse_to(cursor, goal);
12729            });
12730        });
12731    }
12732
12733    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12734        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12735        let text_layout_details = &self.text_layout_details(window);
12736        self.change_selections(Default::default(), window, cx, |s| {
12737            s.move_heads_with(|map, head, goal| {
12738                movement::up(map, head, goal, false, text_layout_details)
12739            })
12740        })
12741    }
12742
12743    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12744        self.take_rename(true, window, cx);
12745
12746        if self.mode.is_single_line() {
12747            cx.propagate();
12748            return;
12749        }
12750
12751        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12752
12753        let text_layout_details = &self.text_layout_details(window);
12754        let selection_count = self.selections.count();
12755        let first_selection = self.selections.first_anchor();
12756
12757        self.change_selections(Default::default(), window, cx, |s| {
12758            s.move_with(|map, selection| {
12759                if !selection.is_empty() {
12760                    selection.goal = SelectionGoal::None;
12761                }
12762                let (cursor, goal) = movement::down(
12763                    map,
12764                    selection.end,
12765                    selection.goal,
12766                    false,
12767                    text_layout_details,
12768                );
12769                selection.collapse_to(cursor, goal);
12770            });
12771        });
12772
12773        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12774        {
12775            cx.propagate();
12776        }
12777    }
12778
12779    pub fn select_page_down(
12780        &mut self,
12781        _: &SelectPageDown,
12782        window: &mut Window,
12783        cx: &mut Context<Self>,
12784    ) {
12785        let Some(row_count) = self.visible_row_count() else {
12786            return;
12787        };
12788
12789        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12790
12791        let text_layout_details = &self.text_layout_details(window);
12792
12793        self.change_selections(Default::default(), window, cx, |s| {
12794            s.move_heads_with(|map, head, goal| {
12795                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12796            })
12797        })
12798    }
12799
12800    pub fn move_page_down(
12801        &mut self,
12802        action: &MovePageDown,
12803        window: &mut Window,
12804        cx: &mut Context<Self>,
12805    ) {
12806        if self.take_rename(true, window, cx).is_some() {
12807            return;
12808        }
12809
12810        if self
12811            .context_menu
12812            .borrow_mut()
12813            .as_mut()
12814            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12815            .unwrap_or(false)
12816        {
12817            return;
12818        }
12819
12820        if matches!(self.mode, EditorMode::SingleLine) {
12821            cx.propagate();
12822            return;
12823        }
12824
12825        let Some(row_count) = self.visible_row_count() else {
12826            return;
12827        };
12828
12829        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12830
12831        let effects = if action.center_cursor {
12832            SelectionEffects::scroll(Autoscroll::center())
12833        } else {
12834            SelectionEffects::default()
12835        };
12836
12837        let text_layout_details = &self.text_layout_details(window);
12838        self.change_selections(effects, window, cx, |s| {
12839            s.move_with(|map, selection| {
12840                if !selection.is_empty() {
12841                    selection.goal = SelectionGoal::None;
12842                }
12843                let (cursor, goal) = movement::down_by_rows(
12844                    map,
12845                    selection.end,
12846                    row_count,
12847                    selection.goal,
12848                    false,
12849                    text_layout_details,
12850                );
12851                selection.collapse_to(cursor, goal);
12852            });
12853        });
12854    }
12855
12856    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12858        let text_layout_details = &self.text_layout_details(window);
12859        self.change_selections(Default::default(), window, cx, |s| {
12860            s.move_heads_with(|map, head, goal| {
12861                movement::down(map, head, goal, false, text_layout_details)
12862            })
12863        });
12864    }
12865
12866    pub fn context_menu_first(
12867        &mut self,
12868        _: &ContextMenuFirst,
12869        window: &mut Window,
12870        cx: &mut Context<Self>,
12871    ) {
12872        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12873            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12874        }
12875    }
12876
12877    pub fn context_menu_prev(
12878        &mut self,
12879        _: &ContextMenuPrevious,
12880        window: &mut Window,
12881        cx: &mut Context<Self>,
12882    ) {
12883        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12884            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12885        }
12886    }
12887
12888    pub fn context_menu_next(
12889        &mut self,
12890        _: &ContextMenuNext,
12891        window: &mut Window,
12892        cx: &mut Context<Self>,
12893    ) {
12894        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12895            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12896        }
12897    }
12898
12899    pub fn context_menu_last(
12900        &mut self,
12901        _: &ContextMenuLast,
12902        window: &mut Window,
12903        cx: &mut Context<Self>,
12904    ) {
12905        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12906            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12907        }
12908    }
12909
12910    pub fn signature_help_prev(
12911        &mut self,
12912        _: &SignatureHelpPrevious,
12913        _: &mut Window,
12914        cx: &mut Context<Self>,
12915    ) {
12916        if let Some(popover) = self.signature_help_state.popover_mut() {
12917            if popover.current_signature == 0 {
12918                popover.current_signature = popover.signatures.len() - 1;
12919            } else {
12920                popover.current_signature -= 1;
12921            }
12922            cx.notify();
12923        }
12924    }
12925
12926    pub fn signature_help_next(
12927        &mut self,
12928        _: &SignatureHelpNext,
12929        _: &mut Window,
12930        cx: &mut Context<Self>,
12931    ) {
12932        if let Some(popover) = self.signature_help_state.popover_mut() {
12933            if popover.current_signature + 1 == popover.signatures.len() {
12934                popover.current_signature = 0;
12935            } else {
12936                popover.current_signature += 1;
12937            }
12938            cx.notify();
12939        }
12940    }
12941
12942    pub fn move_to_previous_word_start(
12943        &mut self,
12944        _: &MoveToPreviousWordStart,
12945        window: &mut Window,
12946        cx: &mut Context<Self>,
12947    ) {
12948        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12949        self.change_selections(Default::default(), window, cx, |s| {
12950            s.move_cursors_with(|map, head, _| {
12951                (
12952                    movement::previous_word_start(map, head),
12953                    SelectionGoal::None,
12954                )
12955            });
12956        })
12957    }
12958
12959    pub fn move_to_previous_subword_start(
12960        &mut self,
12961        _: &MoveToPreviousSubwordStart,
12962        window: &mut Window,
12963        cx: &mut Context<Self>,
12964    ) {
12965        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12966        self.change_selections(Default::default(), window, cx, |s| {
12967            s.move_cursors_with(|map, head, _| {
12968                (
12969                    movement::previous_subword_start(map, head),
12970                    SelectionGoal::None,
12971                )
12972            });
12973        })
12974    }
12975
12976    pub fn select_to_previous_word_start(
12977        &mut self,
12978        _: &SelectToPreviousWordStart,
12979        window: &mut Window,
12980        cx: &mut Context<Self>,
12981    ) {
12982        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12983        self.change_selections(Default::default(), window, cx, |s| {
12984            s.move_heads_with(|map, head, _| {
12985                (
12986                    movement::previous_word_start(map, head),
12987                    SelectionGoal::None,
12988                )
12989            });
12990        })
12991    }
12992
12993    pub fn select_to_previous_subword_start(
12994        &mut self,
12995        _: &SelectToPreviousSubwordStart,
12996        window: &mut Window,
12997        cx: &mut Context<Self>,
12998    ) {
12999        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13000        self.change_selections(Default::default(), window, cx, |s| {
13001            s.move_heads_with(|map, head, _| {
13002                (
13003                    movement::previous_subword_start(map, head),
13004                    SelectionGoal::None,
13005                )
13006            });
13007        })
13008    }
13009
13010    pub fn delete_to_previous_word_start(
13011        &mut self,
13012        action: &DeleteToPreviousWordStart,
13013        window: &mut Window,
13014        cx: &mut Context<Self>,
13015    ) {
13016        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13017        self.transact(window, cx, |this, window, cx| {
13018            this.select_autoclose_pair(window, cx);
13019            this.change_selections(Default::default(), window, cx, |s| {
13020                s.move_with(|map, selection| {
13021                    if selection.is_empty() {
13022                        let cursor = if action.ignore_newlines {
13023                            movement::previous_word_start(map, selection.head())
13024                        } else {
13025                            movement::previous_word_start_or_newline(map, selection.head())
13026                        };
13027                        selection.set_head(cursor, SelectionGoal::None);
13028                    }
13029                });
13030            });
13031            this.insert("", window, cx);
13032        });
13033    }
13034
13035    pub fn delete_to_previous_subword_start(
13036        &mut self,
13037        _: &DeleteToPreviousSubwordStart,
13038        window: &mut Window,
13039        cx: &mut Context<Self>,
13040    ) {
13041        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13042        self.transact(window, cx, |this, window, cx| {
13043            this.select_autoclose_pair(window, cx);
13044            this.change_selections(Default::default(), window, cx, |s| {
13045                s.move_with(|map, selection| {
13046                    if selection.is_empty() {
13047                        let cursor = movement::previous_subword_start(map, selection.head());
13048                        selection.set_head(cursor, SelectionGoal::None);
13049                    }
13050                });
13051            });
13052            this.insert("", window, cx);
13053        });
13054    }
13055
13056    pub fn move_to_next_word_end(
13057        &mut self,
13058        _: &MoveToNextWordEnd,
13059        window: &mut Window,
13060        cx: &mut Context<Self>,
13061    ) {
13062        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13063        self.change_selections(Default::default(), window, cx, |s| {
13064            s.move_cursors_with(|map, head, _| {
13065                (movement::next_word_end(map, head), SelectionGoal::None)
13066            });
13067        })
13068    }
13069
13070    pub fn move_to_next_subword_end(
13071        &mut self,
13072        _: &MoveToNextSubwordEnd,
13073        window: &mut Window,
13074        cx: &mut Context<Self>,
13075    ) {
13076        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13077        self.change_selections(Default::default(), window, cx, |s| {
13078            s.move_cursors_with(|map, head, _| {
13079                (movement::next_subword_end(map, head), SelectionGoal::None)
13080            });
13081        })
13082    }
13083
13084    pub fn select_to_next_word_end(
13085        &mut self,
13086        _: &SelectToNextWordEnd,
13087        window: &mut Window,
13088        cx: &mut Context<Self>,
13089    ) {
13090        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13091        self.change_selections(Default::default(), window, cx, |s| {
13092            s.move_heads_with(|map, head, _| {
13093                (movement::next_word_end(map, head), SelectionGoal::None)
13094            });
13095        })
13096    }
13097
13098    pub fn select_to_next_subword_end(
13099        &mut self,
13100        _: &SelectToNextSubwordEnd,
13101        window: &mut Window,
13102        cx: &mut Context<Self>,
13103    ) {
13104        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13105        self.change_selections(Default::default(), window, cx, |s| {
13106            s.move_heads_with(|map, head, _| {
13107                (movement::next_subword_end(map, head), SelectionGoal::None)
13108            });
13109        })
13110    }
13111
13112    pub fn delete_to_next_word_end(
13113        &mut self,
13114        action: &DeleteToNextWordEnd,
13115        window: &mut Window,
13116        cx: &mut Context<Self>,
13117    ) {
13118        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13119        self.transact(window, cx, |this, window, cx| {
13120            this.change_selections(Default::default(), window, cx, |s| {
13121                s.move_with(|map, selection| {
13122                    if selection.is_empty() {
13123                        let cursor = if action.ignore_newlines {
13124                            movement::next_word_end(map, selection.head())
13125                        } else {
13126                            movement::next_word_end_or_newline(map, selection.head())
13127                        };
13128                        selection.set_head(cursor, SelectionGoal::None);
13129                    }
13130                });
13131            });
13132            this.insert("", window, cx);
13133        });
13134    }
13135
13136    pub fn delete_to_next_subword_end(
13137        &mut self,
13138        _: &DeleteToNextSubwordEnd,
13139        window: &mut Window,
13140        cx: &mut Context<Self>,
13141    ) {
13142        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13143        self.transact(window, cx, |this, window, cx| {
13144            this.change_selections(Default::default(), window, cx, |s| {
13145                s.move_with(|map, selection| {
13146                    if selection.is_empty() {
13147                        let cursor = movement::next_subword_end(map, selection.head());
13148                        selection.set_head(cursor, SelectionGoal::None);
13149                    }
13150                });
13151            });
13152            this.insert("", window, cx);
13153        });
13154    }
13155
13156    pub fn move_to_beginning_of_line(
13157        &mut self,
13158        action: &MoveToBeginningOfLine,
13159        window: &mut Window,
13160        cx: &mut Context<Self>,
13161    ) {
13162        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13163        self.change_selections(Default::default(), window, cx, |s| {
13164            s.move_cursors_with(|map, head, _| {
13165                (
13166                    movement::indented_line_beginning(
13167                        map,
13168                        head,
13169                        action.stop_at_soft_wraps,
13170                        action.stop_at_indent,
13171                    ),
13172                    SelectionGoal::None,
13173                )
13174            });
13175        })
13176    }
13177
13178    pub fn select_to_beginning_of_line(
13179        &mut self,
13180        action: &SelectToBeginningOfLine,
13181        window: &mut Window,
13182        cx: &mut Context<Self>,
13183    ) {
13184        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13185        self.change_selections(Default::default(), window, cx, |s| {
13186            s.move_heads_with(|map, head, _| {
13187                (
13188                    movement::indented_line_beginning(
13189                        map,
13190                        head,
13191                        action.stop_at_soft_wraps,
13192                        action.stop_at_indent,
13193                    ),
13194                    SelectionGoal::None,
13195                )
13196            });
13197        });
13198    }
13199
13200    pub fn delete_to_beginning_of_line(
13201        &mut self,
13202        action: &DeleteToBeginningOfLine,
13203        window: &mut Window,
13204        cx: &mut Context<Self>,
13205    ) {
13206        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13207        self.transact(window, cx, |this, window, cx| {
13208            this.change_selections(Default::default(), window, cx, |s| {
13209                s.move_with(|_, selection| {
13210                    selection.reversed = true;
13211                });
13212            });
13213
13214            this.select_to_beginning_of_line(
13215                &SelectToBeginningOfLine {
13216                    stop_at_soft_wraps: false,
13217                    stop_at_indent: action.stop_at_indent,
13218                },
13219                window,
13220                cx,
13221            );
13222            this.backspace(&Backspace, window, cx);
13223        });
13224    }
13225
13226    pub fn move_to_end_of_line(
13227        &mut self,
13228        action: &MoveToEndOfLine,
13229        window: &mut Window,
13230        cx: &mut Context<Self>,
13231    ) {
13232        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13233        self.change_selections(Default::default(), window, cx, |s| {
13234            s.move_cursors_with(|map, head, _| {
13235                (
13236                    movement::line_end(map, head, action.stop_at_soft_wraps),
13237                    SelectionGoal::None,
13238                )
13239            });
13240        })
13241    }
13242
13243    pub fn select_to_end_of_line(
13244        &mut self,
13245        action: &SelectToEndOfLine,
13246        window: &mut Window,
13247        cx: &mut Context<Self>,
13248    ) {
13249        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13250        self.change_selections(Default::default(), window, cx, |s| {
13251            s.move_heads_with(|map, head, _| {
13252                (
13253                    movement::line_end(map, head, action.stop_at_soft_wraps),
13254                    SelectionGoal::None,
13255                )
13256            });
13257        })
13258    }
13259
13260    pub fn delete_to_end_of_line(
13261        &mut self,
13262        _: &DeleteToEndOfLine,
13263        window: &mut Window,
13264        cx: &mut Context<Self>,
13265    ) {
13266        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13267        self.transact(window, cx, |this, window, cx| {
13268            this.select_to_end_of_line(
13269                &SelectToEndOfLine {
13270                    stop_at_soft_wraps: false,
13271                },
13272                window,
13273                cx,
13274            );
13275            this.delete(&Delete, window, cx);
13276        });
13277    }
13278
13279    pub fn cut_to_end_of_line(
13280        &mut self,
13281        _: &CutToEndOfLine,
13282        window: &mut Window,
13283        cx: &mut Context<Self>,
13284    ) {
13285        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13286        self.transact(window, cx, |this, window, cx| {
13287            this.select_to_end_of_line(
13288                &SelectToEndOfLine {
13289                    stop_at_soft_wraps: false,
13290                },
13291                window,
13292                cx,
13293            );
13294            this.cut(&Cut, window, cx);
13295        });
13296    }
13297
13298    pub fn move_to_start_of_paragraph(
13299        &mut self,
13300        _: &MoveToStartOfParagraph,
13301        window: &mut Window,
13302        cx: &mut Context<Self>,
13303    ) {
13304        if matches!(self.mode, EditorMode::SingleLine) {
13305            cx.propagate();
13306            return;
13307        }
13308        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13309        self.change_selections(Default::default(), window, cx, |s| {
13310            s.move_with(|map, selection| {
13311                selection.collapse_to(
13312                    movement::start_of_paragraph(map, selection.head(), 1),
13313                    SelectionGoal::None,
13314                )
13315            });
13316        })
13317    }
13318
13319    pub fn move_to_end_of_paragraph(
13320        &mut self,
13321        _: &MoveToEndOfParagraph,
13322        window: &mut Window,
13323        cx: &mut Context<Self>,
13324    ) {
13325        if matches!(self.mode, EditorMode::SingleLine) {
13326            cx.propagate();
13327            return;
13328        }
13329        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13330        self.change_selections(Default::default(), window, cx, |s| {
13331            s.move_with(|map, selection| {
13332                selection.collapse_to(
13333                    movement::end_of_paragraph(map, selection.head(), 1),
13334                    SelectionGoal::None,
13335                )
13336            });
13337        })
13338    }
13339
13340    pub fn select_to_start_of_paragraph(
13341        &mut self,
13342        _: &SelectToStartOfParagraph,
13343        window: &mut Window,
13344        cx: &mut Context<Self>,
13345    ) {
13346        if matches!(self.mode, EditorMode::SingleLine) {
13347            cx.propagate();
13348            return;
13349        }
13350        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13351        self.change_selections(Default::default(), window, cx, |s| {
13352            s.move_heads_with(|map, head, _| {
13353                (
13354                    movement::start_of_paragraph(map, head, 1),
13355                    SelectionGoal::None,
13356                )
13357            });
13358        })
13359    }
13360
13361    pub fn select_to_end_of_paragraph(
13362        &mut self,
13363        _: &SelectToEndOfParagraph,
13364        window: &mut Window,
13365        cx: &mut Context<Self>,
13366    ) {
13367        if matches!(self.mode, EditorMode::SingleLine) {
13368            cx.propagate();
13369            return;
13370        }
13371        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13372        self.change_selections(Default::default(), window, cx, |s| {
13373            s.move_heads_with(|map, head, _| {
13374                (
13375                    movement::end_of_paragraph(map, head, 1),
13376                    SelectionGoal::None,
13377                )
13378            });
13379        })
13380    }
13381
13382    pub fn move_to_start_of_excerpt(
13383        &mut self,
13384        _: &MoveToStartOfExcerpt,
13385        window: &mut Window,
13386        cx: &mut Context<Self>,
13387    ) {
13388        if matches!(self.mode, EditorMode::SingleLine) {
13389            cx.propagate();
13390            return;
13391        }
13392        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13393        self.change_selections(Default::default(), window, cx, |s| {
13394            s.move_with(|map, selection| {
13395                selection.collapse_to(
13396                    movement::start_of_excerpt(
13397                        map,
13398                        selection.head(),
13399                        workspace::searchable::Direction::Prev,
13400                    ),
13401                    SelectionGoal::None,
13402                )
13403            });
13404        })
13405    }
13406
13407    pub fn move_to_start_of_next_excerpt(
13408        &mut self,
13409        _: &MoveToStartOfNextExcerpt,
13410        window: &mut Window,
13411        cx: &mut Context<Self>,
13412    ) {
13413        if matches!(self.mode, EditorMode::SingleLine) {
13414            cx.propagate();
13415            return;
13416        }
13417
13418        self.change_selections(Default::default(), window, cx, |s| {
13419            s.move_with(|map, selection| {
13420                selection.collapse_to(
13421                    movement::start_of_excerpt(
13422                        map,
13423                        selection.head(),
13424                        workspace::searchable::Direction::Next,
13425                    ),
13426                    SelectionGoal::None,
13427                )
13428            });
13429        })
13430    }
13431
13432    pub fn move_to_end_of_excerpt(
13433        &mut self,
13434        _: &MoveToEndOfExcerpt,
13435        window: &mut Window,
13436        cx: &mut Context<Self>,
13437    ) {
13438        if matches!(self.mode, EditorMode::SingleLine) {
13439            cx.propagate();
13440            return;
13441        }
13442        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13443        self.change_selections(Default::default(), window, cx, |s| {
13444            s.move_with(|map, selection| {
13445                selection.collapse_to(
13446                    movement::end_of_excerpt(
13447                        map,
13448                        selection.head(),
13449                        workspace::searchable::Direction::Next,
13450                    ),
13451                    SelectionGoal::None,
13452                )
13453            });
13454        })
13455    }
13456
13457    pub fn move_to_end_of_previous_excerpt(
13458        &mut self,
13459        _: &MoveToEndOfPreviousExcerpt,
13460        window: &mut Window,
13461        cx: &mut Context<Self>,
13462    ) {
13463        if matches!(self.mode, EditorMode::SingleLine) {
13464            cx.propagate();
13465            return;
13466        }
13467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13468        self.change_selections(Default::default(), window, cx, |s| {
13469            s.move_with(|map, selection| {
13470                selection.collapse_to(
13471                    movement::end_of_excerpt(
13472                        map,
13473                        selection.head(),
13474                        workspace::searchable::Direction::Prev,
13475                    ),
13476                    SelectionGoal::None,
13477                )
13478            });
13479        })
13480    }
13481
13482    pub fn select_to_start_of_excerpt(
13483        &mut self,
13484        _: &SelectToStartOfExcerpt,
13485        window: &mut Window,
13486        cx: &mut Context<Self>,
13487    ) {
13488        if matches!(self.mode, EditorMode::SingleLine) {
13489            cx.propagate();
13490            return;
13491        }
13492        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13493        self.change_selections(Default::default(), window, cx, |s| {
13494            s.move_heads_with(|map, head, _| {
13495                (
13496                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13497                    SelectionGoal::None,
13498                )
13499            });
13500        })
13501    }
13502
13503    pub fn select_to_start_of_next_excerpt(
13504        &mut self,
13505        _: &SelectToStartOfNextExcerpt,
13506        window: &mut Window,
13507        cx: &mut Context<Self>,
13508    ) {
13509        if matches!(self.mode, EditorMode::SingleLine) {
13510            cx.propagate();
13511            return;
13512        }
13513        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13514        self.change_selections(Default::default(), window, cx, |s| {
13515            s.move_heads_with(|map, head, _| {
13516                (
13517                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13518                    SelectionGoal::None,
13519                )
13520            });
13521        })
13522    }
13523
13524    pub fn select_to_end_of_excerpt(
13525        &mut self,
13526        _: &SelectToEndOfExcerpt,
13527        window: &mut Window,
13528        cx: &mut Context<Self>,
13529    ) {
13530        if matches!(self.mode, EditorMode::SingleLine) {
13531            cx.propagate();
13532            return;
13533        }
13534        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13535        self.change_selections(Default::default(), window, cx, |s| {
13536            s.move_heads_with(|map, head, _| {
13537                (
13538                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13539                    SelectionGoal::None,
13540                )
13541            });
13542        })
13543    }
13544
13545    pub fn select_to_end_of_previous_excerpt(
13546        &mut self,
13547        _: &SelectToEndOfPreviousExcerpt,
13548        window: &mut Window,
13549        cx: &mut Context<Self>,
13550    ) {
13551        if matches!(self.mode, EditorMode::SingleLine) {
13552            cx.propagate();
13553            return;
13554        }
13555        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13556        self.change_selections(Default::default(), window, cx, |s| {
13557            s.move_heads_with(|map, head, _| {
13558                (
13559                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13560                    SelectionGoal::None,
13561                )
13562            });
13563        })
13564    }
13565
13566    pub fn move_to_beginning(
13567        &mut self,
13568        _: &MoveToBeginning,
13569        window: &mut Window,
13570        cx: &mut Context<Self>,
13571    ) {
13572        if matches!(self.mode, EditorMode::SingleLine) {
13573            cx.propagate();
13574            return;
13575        }
13576        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13577        self.change_selections(Default::default(), window, cx, |s| {
13578            s.select_ranges(vec![0..0]);
13579        });
13580    }
13581
13582    pub fn select_to_beginning(
13583        &mut self,
13584        _: &SelectToBeginning,
13585        window: &mut Window,
13586        cx: &mut Context<Self>,
13587    ) {
13588        let mut selection = self.selections.last::<Point>(cx);
13589        selection.set_head(Point::zero(), SelectionGoal::None);
13590        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13591        self.change_selections(Default::default(), window, cx, |s| {
13592            s.select(vec![selection]);
13593        });
13594    }
13595
13596    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13597        if matches!(self.mode, EditorMode::SingleLine) {
13598            cx.propagate();
13599            return;
13600        }
13601        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13602        let cursor = self.buffer.read(cx).read(cx).len();
13603        self.change_selections(Default::default(), window, cx, |s| {
13604            s.select_ranges(vec![cursor..cursor])
13605        });
13606    }
13607
13608    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13609        self.nav_history = nav_history;
13610    }
13611
13612    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13613        self.nav_history.as_ref()
13614    }
13615
13616    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13617        self.push_to_nav_history(
13618            self.selections.newest_anchor().head(),
13619            None,
13620            false,
13621            true,
13622            cx,
13623        );
13624    }
13625
13626    fn push_to_nav_history(
13627        &mut self,
13628        cursor_anchor: Anchor,
13629        new_position: Option<Point>,
13630        is_deactivate: bool,
13631        always: bool,
13632        cx: &mut Context<Self>,
13633    ) {
13634        if let Some(nav_history) = self.nav_history.as_mut() {
13635            let buffer = self.buffer.read(cx).read(cx);
13636            let cursor_position = cursor_anchor.to_point(&buffer);
13637            let scroll_state = self.scroll_manager.anchor();
13638            let scroll_top_row = scroll_state.top_row(&buffer);
13639            drop(buffer);
13640
13641            if let Some(new_position) = new_position {
13642                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13643                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13644                    return;
13645                }
13646            }
13647
13648            nav_history.push(
13649                Some(NavigationData {
13650                    cursor_anchor,
13651                    cursor_position,
13652                    scroll_anchor: scroll_state,
13653                    scroll_top_row,
13654                }),
13655                cx,
13656            );
13657            cx.emit(EditorEvent::PushedToNavHistory {
13658                anchor: cursor_anchor,
13659                is_deactivate,
13660            })
13661        }
13662    }
13663
13664    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13665        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13666        let buffer = self.buffer.read(cx).snapshot(cx);
13667        let mut selection = self.selections.first::<usize>(cx);
13668        selection.set_head(buffer.len(), SelectionGoal::None);
13669        self.change_selections(Default::default(), window, cx, |s| {
13670            s.select(vec![selection]);
13671        });
13672    }
13673
13674    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13675        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13676        let end = self.buffer.read(cx).read(cx).len();
13677        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13678            s.select_ranges(vec![0..end]);
13679        });
13680    }
13681
13682    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13684        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13685        let mut selections = self.selections.all::<Point>(cx);
13686        let max_point = display_map.buffer_snapshot.max_point();
13687        for selection in &mut selections {
13688            let rows = selection.spanned_rows(true, &display_map);
13689            selection.start = Point::new(rows.start.0, 0);
13690            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13691            selection.reversed = false;
13692        }
13693        self.change_selections(Default::default(), window, cx, |s| {
13694            s.select(selections);
13695        });
13696    }
13697
13698    pub fn split_selection_into_lines(
13699        &mut self,
13700        action: &SplitSelectionIntoLines,
13701        window: &mut Window,
13702        cx: &mut Context<Self>,
13703    ) {
13704        let selections = self
13705            .selections
13706            .all::<Point>(cx)
13707            .into_iter()
13708            .map(|selection| selection.start..selection.end)
13709            .collect::<Vec<_>>();
13710        self.unfold_ranges(&selections, true, true, cx);
13711
13712        let mut new_selection_ranges = Vec::new();
13713        {
13714            let buffer = self.buffer.read(cx).read(cx);
13715            for selection in selections {
13716                for row in selection.start.row..selection.end.row {
13717                    let line_start = Point::new(row, 0);
13718                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13719
13720                    if action.keep_selections {
13721                        // Keep the selection range for each line
13722                        let selection_start = if row == selection.start.row {
13723                            selection.start
13724                        } else {
13725                            line_start
13726                        };
13727                        new_selection_ranges.push(selection_start..line_end);
13728                    } else {
13729                        // Collapse to cursor at end of line
13730                        new_selection_ranges.push(line_end..line_end);
13731                    }
13732                }
13733
13734                let is_multiline_selection = selection.start.row != selection.end.row;
13735                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13736                // so this action feels more ergonomic when paired with other selection operations
13737                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13738                if !should_skip_last {
13739                    if action.keep_selections {
13740                        if is_multiline_selection {
13741                            let line_start = Point::new(selection.end.row, 0);
13742                            new_selection_ranges.push(line_start..selection.end);
13743                        } else {
13744                            new_selection_ranges.push(selection.start..selection.end);
13745                        }
13746                    } else {
13747                        new_selection_ranges.push(selection.end..selection.end);
13748                    }
13749                }
13750            }
13751        }
13752        self.change_selections(Default::default(), window, cx, |s| {
13753            s.select_ranges(new_selection_ranges);
13754        });
13755    }
13756
13757    pub fn add_selection_above(
13758        &mut self,
13759        _: &AddSelectionAbove,
13760        window: &mut Window,
13761        cx: &mut Context<Self>,
13762    ) {
13763        self.add_selection(true, window, cx);
13764    }
13765
13766    pub fn add_selection_below(
13767        &mut self,
13768        _: &AddSelectionBelow,
13769        window: &mut Window,
13770        cx: &mut Context<Self>,
13771    ) {
13772        self.add_selection(false, window, cx);
13773    }
13774
13775    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13776        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13777
13778        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13779        let all_selections = self.selections.all::<Point>(cx);
13780        let text_layout_details = self.text_layout_details(window);
13781
13782        let (mut columnar_selections, new_selections_to_columnarize) = {
13783            if let Some(state) = self.add_selections_state.as_ref() {
13784                let columnar_selection_ids: HashSet<_> = state
13785                    .groups
13786                    .iter()
13787                    .flat_map(|group| group.stack.iter())
13788                    .copied()
13789                    .collect();
13790
13791                all_selections
13792                    .into_iter()
13793                    .partition(|s| columnar_selection_ids.contains(&s.id))
13794            } else {
13795                (Vec::new(), all_selections)
13796            }
13797        };
13798
13799        let mut state = self
13800            .add_selections_state
13801            .take()
13802            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13803
13804        for selection in new_selections_to_columnarize {
13805            let range = selection.display_range(&display_map).sorted();
13806            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13807            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13808            let positions = start_x.min(end_x)..start_x.max(end_x);
13809            let mut stack = Vec::new();
13810            for row in range.start.row().0..=range.end.row().0 {
13811                if let Some(selection) = self.selections.build_columnar_selection(
13812                    &display_map,
13813                    DisplayRow(row),
13814                    &positions,
13815                    selection.reversed,
13816                    &text_layout_details,
13817                ) {
13818                    stack.push(selection.id);
13819                    columnar_selections.push(selection);
13820                }
13821            }
13822            if !stack.is_empty() {
13823                if above {
13824                    stack.reverse();
13825                }
13826                state.groups.push(AddSelectionsGroup { above, stack });
13827            }
13828        }
13829
13830        let mut final_selections = Vec::new();
13831        let end_row = if above {
13832            DisplayRow(0)
13833        } else {
13834            display_map.max_point().row()
13835        };
13836
13837        let mut last_added_item_per_group = HashMap::default();
13838        for group in state.groups.iter_mut() {
13839            if let Some(last_id) = group.stack.last() {
13840                last_added_item_per_group.insert(*last_id, group);
13841            }
13842        }
13843
13844        for selection in columnar_selections {
13845            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13846                if above == group.above {
13847                    let range = selection.display_range(&display_map).sorted();
13848                    debug_assert_eq!(range.start.row(), range.end.row());
13849                    let mut row = range.start.row();
13850                    let positions =
13851                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13852                            px(start)..px(end)
13853                        } else {
13854                            let start_x =
13855                                display_map.x_for_display_point(range.start, &text_layout_details);
13856                            let end_x =
13857                                display_map.x_for_display_point(range.end, &text_layout_details);
13858                            start_x.min(end_x)..start_x.max(end_x)
13859                        };
13860
13861                    let mut maybe_new_selection = None;
13862                    while row != end_row {
13863                        if above {
13864                            row.0 -= 1;
13865                        } else {
13866                            row.0 += 1;
13867                        }
13868                        if let Some(new_selection) = self.selections.build_columnar_selection(
13869                            &display_map,
13870                            row,
13871                            &positions,
13872                            selection.reversed,
13873                            &text_layout_details,
13874                        ) {
13875                            maybe_new_selection = Some(new_selection);
13876                            break;
13877                        }
13878                    }
13879
13880                    if let Some(new_selection) = maybe_new_selection {
13881                        group.stack.push(new_selection.id);
13882                        if above {
13883                            final_selections.push(new_selection);
13884                            final_selections.push(selection);
13885                        } else {
13886                            final_selections.push(selection);
13887                            final_selections.push(new_selection);
13888                        }
13889                    } else {
13890                        final_selections.push(selection);
13891                    }
13892                } else {
13893                    group.stack.pop();
13894                }
13895            } else {
13896                final_selections.push(selection);
13897            }
13898        }
13899
13900        self.change_selections(Default::default(), window, cx, |s| {
13901            s.select(final_selections);
13902        });
13903
13904        let final_selection_ids: HashSet<_> = self
13905            .selections
13906            .all::<Point>(cx)
13907            .iter()
13908            .map(|s| s.id)
13909            .collect();
13910        state.groups.retain_mut(|group| {
13911            // selections might get merged above so we remove invalid items from stacks
13912            group.stack.retain(|id| final_selection_ids.contains(id));
13913
13914            // single selection in stack can be treated as initial state
13915            group.stack.len() > 1
13916        });
13917
13918        if !state.groups.is_empty() {
13919            self.add_selections_state = Some(state);
13920        }
13921    }
13922
13923    fn select_match_ranges(
13924        &mut self,
13925        range: Range<usize>,
13926        reversed: bool,
13927        replace_newest: bool,
13928        auto_scroll: Option<Autoscroll>,
13929        window: &mut Window,
13930        cx: &mut Context<Editor>,
13931    ) {
13932        self.unfold_ranges(
13933            std::slice::from_ref(&range),
13934            false,
13935            auto_scroll.is_some(),
13936            cx,
13937        );
13938        let effects = if let Some(scroll) = auto_scroll {
13939            SelectionEffects::scroll(scroll)
13940        } else {
13941            SelectionEffects::no_scroll()
13942        };
13943        self.change_selections(effects, window, cx, |s| {
13944            if replace_newest {
13945                s.delete(s.newest_anchor().id);
13946            }
13947            if reversed {
13948                s.insert_range(range.end..range.start);
13949            } else {
13950                s.insert_range(range);
13951            }
13952        });
13953    }
13954
13955    pub fn select_next_match_internal(
13956        &mut self,
13957        display_map: &DisplaySnapshot,
13958        replace_newest: bool,
13959        autoscroll: Option<Autoscroll>,
13960        window: &mut Window,
13961        cx: &mut Context<Self>,
13962    ) -> Result<()> {
13963        let buffer = &display_map.buffer_snapshot;
13964        let mut selections = self.selections.all::<usize>(cx);
13965        if let Some(mut select_next_state) = self.select_next_state.take() {
13966            let query = &select_next_state.query;
13967            if !select_next_state.done {
13968                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13969                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13970                let mut next_selected_range = None;
13971
13972                let bytes_after_last_selection =
13973                    buffer.bytes_in_range(last_selection.end..buffer.len());
13974                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13975                let query_matches = query
13976                    .stream_find_iter(bytes_after_last_selection)
13977                    .map(|result| (last_selection.end, result))
13978                    .chain(
13979                        query
13980                            .stream_find_iter(bytes_before_first_selection)
13981                            .map(|result| (0, result)),
13982                    );
13983
13984                for (start_offset, query_match) in query_matches {
13985                    let query_match = query_match.unwrap(); // can only fail due to I/O
13986                    let offset_range =
13987                        start_offset + query_match.start()..start_offset + query_match.end();
13988
13989                    if !select_next_state.wordwise
13990                        || (!buffer.is_inside_word(offset_range.start, false)
13991                            && !buffer.is_inside_word(offset_range.end, false))
13992                    {
13993                        // TODO: This is n^2, because we might check all the selections
13994                        if !selections
13995                            .iter()
13996                            .any(|selection| selection.range().overlaps(&offset_range))
13997                        {
13998                            next_selected_range = Some(offset_range);
13999                            break;
14000                        }
14001                    }
14002                }
14003
14004                if let Some(next_selected_range) = next_selected_range {
14005                    self.select_match_ranges(
14006                        next_selected_range,
14007                        last_selection.reversed,
14008                        replace_newest,
14009                        autoscroll,
14010                        window,
14011                        cx,
14012                    );
14013                } else {
14014                    select_next_state.done = true;
14015                }
14016            }
14017
14018            self.select_next_state = Some(select_next_state);
14019        } else {
14020            let mut only_carets = true;
14021            let mut same_text_selected = true;
14022            let mut selected_text = None;
14023
14024            let mut selections_iter = selections.iter().peekable();
14025            while let Some(selection) = selections_iter.next() {
14026                if selection.start != selection.end {
14027                    only_carets = false;
14028                }
14029
14030                if same_text_selected {
14031                    if selected_text.is_none() {
14032                        selected_text =
14033                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14034                    }
14035
14036                    if let Some(next_selection) = selections_iter.peek() {
14037                        if next_selection.range().len() == selection.range().len() {
14038                            let next_selected_text = buffer
14039                                .text_for_range(next_selection.range())
14040                                .collect::<String>();
14041                            if Some(next_selected_text) != selected_text {
14042                                same_text_selected = false;
14043                                selected_text = None;
14044                            }
14045                        } else {
14046                            same_text_selected = false;
14047                            selected_text = None;
14048                        }
14049                    }
14050                }
14051            }
14052
14053            if only_carets {
14054                for selection in &mut selections {
14055                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14056                    selection.start = word_range.start;
14057                    selection.end = word_range.end;
14058                    selection.goal = SelectionGoal::None;
14059                    selection.reversed = false;
14060                    self.select_match_ranges(
14061                        selection.start..selection.end,
14062                        selection.reversed,
14063                        replace_newest,
14064                        autoscroll,
14065                        window,
14066                        cx,
14067                    );
14068                }
14069
14070                if selections.len() == 1 {
14071                    let selection = selections
14072                        .last()
14073                        .expect("ensured that there's only one selection");
14074                    let query = buffer
14075                        .text_for_range(selection.start..selection.end)
14076                        .collect::<String>();
14077                    let is_empty = query.is_empty();
14078                    let select_state = SelectNextState {
14079                        query: AhoCorasick::new(&[query])?,
14080                        wordwise: true,
14081                        done: is_empty,
14082                    };
14083                    self.select_next_state = Some(select_state);
14084                } else {
14085                    self.select_next_state = None;
14086                }
14087            } else if let Some(selected_text) = selected_text {
14088                self.select_next_state = Some(SelectNextState {
14089                    query: AhoCorasick::new(&[selected_text])?,
14090                    wordwise: false,
14091                    done: false,
14092                });
14093                self.select_next_match_internal(
14094                    display_map,
14095                    replace_newest,
14096                    autoscroll,
14097                    window,
14098                    cx,
14099                )?;
14100            }
14101        }
14102        Ok(())
14103    }
14104
14105    pub fn select_all_matches(
14106        &mut self,
14107        _action: &SelectAllMatches,
14108        window: &mut Window,
14109        cx: &mut Context<Self>,
14110    ) -> Result<()> {
14111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14112
14113        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14114
14115        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14116        let Some(select_next_state) = self.select_next_state.as_mut() else {
14117            return Ok(());
14118        };
14119        if select_next_state.done {
14120            return Ok(());
14121        }
14122
14123        let mut new_selections = Vec::new();
14124
14125        let reversed = self.selections.oldest::<usize>(cx).reversed;
14126        let buffer = &display_map.buffer_snapshot;
14127        let query_matches = select_next_state
14128            .query
14129            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14130
14131        for query_match in query_matches.into_iter() {
14132            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14133            let offset_range = if reversed {
14134                query_match.end()..query_match.start()
14135            } else {
14136                query_match.start()..query_match.end()
14137            };
14138
14139            if !select_next_state.wordwise
14140                || (!buffer.is_inside_word(offset_range.start, false)
14141                    && !buffer.is_inside_word(offset_range.end, false))
14142            {
14143                new_selections.push(offset_range.start..offset_range.end);
14144            }
14145        }
14146
14147        select_next_state.done = true;
14148
14149        if new_selections.is_empty() {
14150            log::error!("bug: new_selections is empty in select_all_matches");
14151            return Ok(());
14152        }
14153
14154        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14155        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14156            selections.select_ranges(new_selections)
14157        });
14158
14159        Ok(())
14160    }
14161
14162    pub fn select_next(
14163        &mut self,
14164        action: &SelectNext,
14165        window: &mut Window,
14166        cx: &mut Context<Self>,
14167    ) -> Result<()> {
14168        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14169        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14170        self.select_next_match_internal(
14171            &display_map,
14172            action.replace_newest,
14173            Some(Autoscroll::newest()),
14174            window,
14175            cx,
14176        )?;
14177        Ok(())
14178    }
14179
14180    pub fn select_previous(
14181        &mut self,
14182        action: &SelectPrevious,
14183        window: &mut Window,
14184        cx: &mut Context<Self>,
14185    ) -> Result<()> {
14186        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14187        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14188        let buffer = &display_map.buffer_snapshot;
14189        let mut selections = self.selections.all::<usize>(cx);
14190        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14191            let query = &select_prev_state.query;
14192            if !select_prev_state.done {
14193                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14194                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14195                let mut next_selected_range = None;
14196                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14197                let bytes_before_last_selection =
14198                    buffer.reversed_bytes_in_range(0..last_selection.start);
14199                let bytes_after_first_selection =
14200                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14201                let query_matches = query
14202                    .stream_find_iter(bytes_before_last_selection)
14203                    .map(|result| (last_selection.start, result))
14204                    .chain(
14205                        query
14206                            .stream_find_iter(bytes_after_first_selection)
14207                            .map(|result| (buffer.len(), result)),
14208                    );
14209                for (end_offset, query_match) in query_matches {
14210                    let query_match = query_match.unwrap(); // can only fail due to I/O
14211                    let offset_range =
14212                        end_offset - query_match.end()..end_offset - query_match.start();
14213
14214                    if !select_prev_state.wordwise
14215                        || (!buffer.is_inside_word(offset_range.start, false)
14216                            && !buffer.is_inside_word(offset_range.end, false))
14217                    {
14218                        next_selected_range = Some(offset_range);
14219                        break;
14220                    }
14221                }
14222
14223                if let Some(next_selected_range) = next_selected_range {
14224                    self.select_match_ranges(
14225                        next_selected_range,
14226                        last_selection.reversed,
14227                        action.replace_newest,
14228                        Some(Autoscroll::newest()),
14229                        window,
14230                        cx,
14231                    );
14232                } else {
14233                    select_prev_state.done = true;
14234                }
14235            }
14236
14237            self.select_prev_state = Some(select_prev_state);
14238        } else {
14239            let mut only_carets = true;
14240            let mut same_text_selected = true;
14241            let mut selected_text = None;
14242
14243            let mut selections_iter = selections.iter().peekable();
14244            while let Some(selection) = selections_iter.next() {
14245                if selection.start != selection.end {
14246                    only_carets = false;
14247                }
14248
14249                if same_text_selected {
14250                    if selected_text.is_none() {
14251                        selected_text =
14252                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14253                    }
14254
14255                    if let Some(next_selection) = selections_iter.peek() {
14256                        if next_selection.range().len() == selection.range().len() {
14257                            let next_selected_text = buffer
14258                                .text_for_range(next_selection.range())
14259                                .collect::<String>();
14260                            if Some(next_selected_text) != selected_text {
14261                                same_text_selected = false;
14262                                selected_text = None;
14263                            }
14264                        } else {
14265                            same_text_selected = false;
14266                            selected_text = None;
14267                        }
14268                    }
14269                }
14270            }
14271
14272            if only_carets {
14273                for selection in &mut selections {
14274                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14275                    selection.start = word_range.start;
14276                    selection.end = word_range.end;
14277                    selection.goal = SelectionGoal::None;
14278                    selection.reversed = false;
14279                    self.select_match_ranges(
14280                        selection.start..selection.end,
14281                        selection.reversed,
14282                        action.replace_newest,
14283                        Some(Autoscroll::newest()),
14284                        window,
14285                        cx,
14286                    );
14287                }
14288                if selections.len() == 1 {
14289                    let selection = selections
14290                        .last()
14291                        .expect("ensured that there's only one selection");
14292                    let query = buffer
14293                        .text_for_range(selection.start..selection.end)
14294                        .collect::<String>();
14295                    let is_empty = query.is_empty();
14296                    let select_state = SelectNextState {
14297                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14298                        wordwise: true,
14299                        done: is_empty,
14300                    };
14301                    self.select_prev_state = Some(select_state);
14302                } else {
14303                    self.select_prev_state = None;
14304                }
14305            } else if let Some(selected_text) = selected_text {
14306                self.select_prev_state = Some(SelectNextState {
14307                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14308                    wordwise: false,
14309                    done: false,
14310                });
14311                self.select_previous(action, window, cx)?;
14312            }
14313        }
14314        Ok(())
14315    }
14316
14317    pub fn find_next_match(
14318        &mut self,
14319        _: &FindNextMatch,
14320        window: &mut Window,
14321        cx: &mut Context<Self>,
14322    ) -> Result<()> {
14323        let selections = self.selections.disjoint_anchors();
14324        match selections.first() {
14325            Some(first) if selections.len() >= 2 => {
14326                self.change_selections(Default::default(), window, cx, |s| {
14327                    s.select_ranges([first.range()]);
14328                });
14329            }
14330            _ => self.select_next(
14331                &SelectNext {
14332                    replace_newest: true,
14333                },
14334                window,
14335                cx,
14336            )?,
14337        }
14338        Ok(())
14339    }
14340
14341    pub fn find_previous_match(
14342        &mut self,
14343        _: &FindPreviousMatch,
14344        window: &mut Window,
14345        cx: &mut Context<Self>,
14346    ) -> Result<()> {
14347        let selections = self.selections.disjoint_anchors();
14348        match selections.last() {
14349            Some(last) if selections.len() >= 2 => {
14350                self.change_selections(Default::default(), window, cx, |s| {
14351                    s.select_ranges([last.range()]);
14352                });
14353            }
14354            _ => self.select_previous(
14355                &SelectPrevious {
14356                    replace_newest: true,
14357                },
14358                window,
14359                cx,
14360            )?,
14361        }
14362        Ok(())
14363    }
14364
14365    pub fn toggle_comments(
14366        &mut self,
14367        action: &ToggleComments,
14368        window: &mut Window,
14369        cx: &mut Context<Self>,
14370    ) {
14371        if self.read_only(cx) {
14372            return;
14373        }
14374        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14375        let text_layout_details = &self.text_layout_details(window);
14376        self.transact(window, cx, |this, window, cx| {
14377            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14378            let mut edits = Vec::new();
14379            let mut selection_edit_ranges = Vec::new();
14380            let mut last_toggled_row = None;
14381            let snapshot = this.buffer.read(cx).read(cx);
14382            let empty_str: Arc<str> = Arc::default();
14383            let mut suffixes_inserted = Vec::new();
14384            let ignore_indent = action.ignore_indent;
14385
14386            fn comment_prefix_range(
14387                snapshot: &MultiBufferSnapshot,
14388                row: MultiBufferRow,
14389                comment_prefix: &str,
14390                comment_prefix_whitespace: &str,
14391                ignore_indent: bool,
14392            ) -> Range<Point> {
14393                let indent_size = if ignore_indent {
14394                    0
14395                } else {
14396                    snapshot.indent_size_for_line(row).len
14397                };
14398
14399                let start = Point::new(row.0, indent_size);
14400
14401                let mut line_bytes = snapshot
14402                    .bytes_in_range(start..snapshot.max_point())
14403                    .flatten()
14404                    .copied();
14405
14406                // If this line currently begins with the line comment prefix, then record
14407                // the range containing the prefix.
14408                if line_bytes
14409                    .by_ref()
14410                    .take(comment_prefix.len())
14411                    .eq(comment_prefix.bytes())
14412                {
14413                    // Include any whitespace that matches the comment prefix.
14414                    let matching_whitespace_len = line_bytes
14415                        .zip(comment_prefix_whitespace.bytes())
14416                        .take_while(|(a, b)| a == b)
14417                        .count() as u32;
14418                    let end = Point::new(
14419                        start.row,
14420                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14421                    );
14422                    start..end
14423                } else {
14424                    start..start
14425                }
14426            }
14427
14428            fn comment_suffix_range(
14429                snapshot: &MultiBufferSnapshot,
14430                row: MultiBufferRow,
14431                comment_suffix: &str,
14432                comment_suffix_has_leading_space: bool,
14433            ) -> Range<Point> {
14434                let end = Point::new(row.0, snapshot.line_len(row));
14435                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14436
14437                let mut line_end_bytes = snapshot
14438                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14439                    .flatten()
14440                    .copied();
14441
14442                let leading_space_len = if suffix_start_column > 0
14443                    && line_end_bytes.next() == Some(b' ')
14444                    && comment_suffix_has_leading_space
14445                {
14446                    1
14447                } else {
14448                    0
14449                };
14450
14451                // If this line currently begins with the line comment prefix, then record
14452                // the range containing the prefix.
14453                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14454                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14455                    start..end
14456                } else {
14457                    end..end
14458                }
14459            }
14460
14461            // TODO: Handle selections that cross excerpts
14462            for selection in &mut selections {
14463                let start_column = snapshot
14464                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14465                    .len;
14466                let language = if let Some(language) =
14467                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14468                {
14469                    language
14470                } else {
14471                    continue;
14472                };
14473
14474                selection_edit_ranges.clear();
14475
14476                // If multiple selections contain a given row, avoid processing that
14477                // row more than once.
14478                let mut start_row = MultiBufferRow(selection.start.row);
14479                if last_toggled_row == Some(start_row) {
14480                    start_row = start_row.next_row();
14481                }
14482                let end_row =
14483                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14484                        MultiBufferRow(selection.end.row - 1)
14485                    } else {
14486                        MultiBufferRow(selection.end.row)
14487                    };
14488                last_toggled_row = Some(end_row);
14489
14490                if start_row > end_row {
14491                    continue;
14492                }
14493
14494                // If the language has line comments, toggle those.
14495                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14496
14497                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14498                if ignore_indent {
14499                    full_comment_prefixes = full_comment_prefixes
14500                        .into_iter()
14501                        .map(|s| Arc::from(s.trim_end()))
14502                        .collect();
14503                }
14504
14505                if !full_comment_prefixes.is_empty() {
14506                    let first_prefix = full_comment_prefixes
14507                        .first()
14508                        .expect("prefixes is non-empty");
14509                    let prefix_trimmed_lengths = full_comment_prefixes
14510                        .iter()
14511                        .map(|p| p.trim_end_matches(' ').len())
14512                        .collect::<SmallVec<[usize; 4]>>();
14513
14514                    let mut all_selection_lines_are_comments = true;
14515
14516                    for row in start_row.0..=end_row.0 {
14517                        let row = MultiBufferRow(row);
14518                        if start_row < end_row && snapshot.is_line_blank(row) {
14519                            continue;
14520                        }
14521
14522                        let prefix_range = full_comment_prefixes
14523                            .iter()
14524                            .zip(prefix_trimmed_lengths.iter().copied())
14525                            .map(|(prefix, trimmed_prefix_len)| {
14526                                comment_prefix_range(
14527                                    snapshot.deref(),
14528                                    row,
14529                                    &prefix[..trimmed_prefix_len],
14530                                    &prefix[trimmed_prefix_len..],
14531                                    ignore_indent,
14532                                )
14533                            })
14534                            .max_by_key(|range| range.end.column - range.start.column)
14535                            .expect("prefixes is non-empty");
14536
14537                        if prefix_range.is_empty() {
14538                            all_selection_lines_are_comments = false;
14539                        }
14540
14541                        selection_edit_ranges.push(prefix_range);
14542                    }
14543
14544                    if all_selection_lines_are_comments {
14545                        edits.extend(
14546                            selection_edit_ranges
14547                                .iter()
14548                                .cloned()
14549                                .map(|range| (range, empty_str.clone())),
14550                        );
14551                    } else {
14552                        let min_column = selection_edit_ranges
14553                            .iter()
14554                            .map(|range| range.start.column)
14555                            .min()
14556                            .unwrap_or(0);
14557                        edits.extend(selection_edit_ranges.iter().map(|range| {
14558                            let position = Point::new(range.start.row, min_column);
14559                            (position..position, first_prefix.clone())
14560                        }));
14561                    }
14562                } else if let Some(BlockCommentConfig {
14563                    start: full_comment_prefix,
14564                    end: comment_suffix,
14565                    ..
14566                }) = language.block_comment()
14567                {
14568                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14569                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14570                    let prefix_range = comment_prefix_range(
14571                        snapshot.deref(),
14572                        start_row,
14573                        comment_prefix,
14574                        comment_prefix_whitespace,
14575                        ignore_indent,
14576                    );
14577                    let suffix_range = comment_suffix_range(
14578                        snapshot.deref(),
14579                        end_row,
14580                        comment_suffix.trim_start_matches(' '),
14581                        comment_suffix.starts_with(' '),
14582                    );
14583
14584                    if prefix_range.is_empty() || suffix_range.is_empty() {
14585                        edits.push((
14586                            prefix_range.start..prefix_range.start,
14587                            full_comment_prefix.clone(),
14588                        ));
14589                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14590                        suffixes_inserted.push((end_row, comment_suffix.len()));
14591                    } else {
14592                        edits.push((prefix_range, empty_str.clone()));
14593                        edits.push((suffix_range, empty_str.clone()));
14594                    }
14595                } else {
14596                    continue;
14597                }
14598            }
14599
14600            drop(snapshot);
14601            this.buffer.update(cx, |buffer, cx| {
14602                buffer.edit(edits, None, cx);
14603            });
14604
14605            // Adjust selections so that they end before any comment suffixes that
14606            // were inserted.
14607            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14608            let mut selections = this.selections.all::<Point>(cx);
14609            let snapshot = this.buffer.read(cx).read(cx);
14610            for selection in &mut selections {
14611                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14612                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14613                        Ordering::Less => {
14614                            suffixes_inserted.next();
14615                            continue;
14616                        }
14617                        Ordering::Greater => break,
14618                        Ordering::Equal => {
14619                            if selection.end.column == snapshot.line_len(row) {
14620                                if selection.is_empty() {
14621                                    selection.start.column -= suffix_len as u32;
14622                                }
14623                                selection.end.column -= suffix_len as u32;
14624                            }
14625                            break;
14626                        }
14627                    }
14628                }
14629            }
14630
14631            drop(snapshot);
14632            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14633
14634            let selections = this.selections.all::<Point>(cx);
14635            let selections_on_single_row = selections.windows(2).all(|selections| {
14636                selections[0].start.row == selections[1].start.row
14637                    && selections[0].end.row == selections[1].end.row
14638                    && selections[0].start.row == selections[0].end.row
14639            });
14640            let selections_selecting = selections
14641                .iter()
14642                .any(|selection| selection.start != selection.end);
14643            let advance_downwards = action.advance_downwards
14644                && selections_on_single_row
14645                && !selections_selecting
14646                && !matches!(this.mode, EditorMode::SingleLine);
14647
14648            if advance_downwards {
14649                let snapshot = this.buffer.read(cx).snapshot(cx);
14650
14651                this.change_selections(Default::default(), window, cx, |s| {
14652                    s.move_cursors_with(|display_snapshot, display_point, _| {
14653                        let mut point = display_point.to_point(display_snapshot);
14654                        point.row += 1;
14655                        point = snapshot.clip_point(point, Bias::Left);
14656                        let display_point = point.to_display_point(display_snapshot);
14657                        let goal = SelectionGoal::HorizontalPosition(
14658                            display_snapshot
14659                                .x_for_display_point(display_point, text_layout_details)
14660                                .into(),
14661                        );
14662                        (display_point, goal)
14663                    })
14664                });
14665            }
14666        });
14667    }
14668
14669    pub fn select_enclosing_symbol(
14670        &mut self,
14671        _: &SelectEnclosingSymbol,
14672        window: &mut Window,
14673        cx: &mut Context<Self>,
14674    ) {
14675        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14676
14677        let buffer = self.buffer.read(cx).snapshot(cx);
14678        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14679
14680        fn update_selection(
14681            selection: &Selection<usize>,
14682            buffer_snap: &MultiBufferSnapshot,
14683        ) -> Option<Selection<usize>> {
14684            let cursor = selection.head();
14685            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14686            for symbol in symbols.iter().rev() {
14687                let start = symbol.range.start.to_offset(buffer_snap);
14688                let end = symbol.range.end.to_offset(buffer_snap);
14689                let new_range = start..end;
14690                if start < selection.start || end > selection.end {
14691                    return Some(Selection {
14692                        id: selection.id,
14693                        start: new_range.start,
14694                        end: new_range.end,
14695                        goal: SelectionGoal::None,
14696                        reversed: selection.reversed,
14697                    });
14698                }
14699            }
14700            None
14701        }
14702
14703        let mut selected_larger_symbol = false;
14704        let new_selections = old_selections
14705            .iter()
14706            .map(|selection| match update_selection(selection, &buffer) {
14707                Some(new_selection) => {
14708                    if new_selection.range() != selection.range() {
14709                        selected_larger_symbol = true;
14710                    }
14711                    new_selection
14712                }
14713                None => selection.clone(),
14714            })
14715            .collect::<Vec<_>>();
14716
14717        if selected_larger_symbol {
14718            self.change_selections(Default::default(), window, cx, |s| {
14719                s.select(new_selections);
14720            });
14721        }
14722    }
14723
14724    pub fn select_larger_syntax_node(
14725        &mut self,
14726        _: &SelectLargerSyntaxNode,
14727        window: &mut Window,
14728        cx: &mut Context<Self>,
14729    ) {
14730        let Some(visible_row_count) = self.visible_row_count() else {
14731            return;
14732        };
14733        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14734        if old_selections.is_empty() {
14735            return;
14736        }
14737
14738        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14739
14740        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14741        let buffer = self.buffer.read(cx).snapshot(cx);
14742
14743        let mut selected_larger_node = false;
14744        let mut new_selections = old_selections
14745            .iter()
14746            .map(|selection| {
14747                let old_range = selection.start..selection.end;
14748
14749                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14750                    // manually select word at selection
14751                    if ["string_content", "inline"].contains(&node.kind()) {
14752                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14753                        // ignore if word is already selected
14754                        if !word_range.is_empty() && old_range != word_range {
14755                            let (last_word_range, _) =
14756                                buffer.surrounding_word(old_range.end, false);
14757                            // only select word if start and end point belongs to same word
14758                            if word_range == last_word_range {
14759                                selected_larger_node = true;
14760                                return Selection {
14761                                    id: selection.id,
14762                                    start: word_range.start,
14763                                    end: word_range.end,
14764                                    goal: SelectionGoal::None,
14765                                    reversed: selection.reversed,
14766                                };
14767                            }
14768                        }
14769                    }
14770                }
14771
14772                let mut new_range = old_range.clone();
14773                while let Some((_node, containing_range)) =
14774                    buffer.syntax_ancestor(new_range.clone())
14775                {
14776                    new_range = match containing_range {
14777                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14778                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14779                    };
14780                    if !display_map.intersects_fold(new_range.start)
14781                        && !display_map.intersects_fold(new_range.end)
14782                    {
14783                        break;
14784                    }
14785                }
14786
14787                selected_larger_node |= new_range != old_range;
14788                Selection {
14789                    id: selection.id,
14790                    start: new_range.start,
14791                    end: new_range.end,
14792                    goal: SelectionGoal::None,
14793                    reversed: selection.reversed,
14794                }
14795            })
14796            .collect::<Vec<_>>();
14797
14798        if !selected_larger_node {
14799            return; // don't put this call in the history
14800        }
14801
14802        // scroll based on transformation done to the last selection created by the user
14803        let (last_old, last_new) = old_selections
14804            .last()
14805            .zip(new_selections.last().cloned())
14806            .expect("old_selections isn't empty");
14807
14808        // revert selection
14809        let is_selection_reversed = {
14810            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14811            new_selections.last_mut().expect("checked above").reversed =
14812                should_newest_selection_be_reversed;
14813            should_newest_selection_be_reversed
14814        };
14815
14816        if selected_larger_node {
14817            self.select_syntax_node_history.disable_clearing = true;
14818            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14819                s.select(new_selections.clone());
14820            });
14821            self.select_syntax_node_history.disable_clearing = false;
14822        }
14823
14824        let start_row = last_new.start.to_display_point(&display_map).row().0;
14825        let end_row = last_new.end.to_display_point(&display_map).row().0;
14826        let selection_height = end_row - start_row + 1;
14827        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14828
14829        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14830        let scroll_behavior = if fits_on_the_screen {
14831            self.request_autoscroll(Autoscroll::fit(), cx);
14832            SelectSyntaxNodeScrollBehavior::FitSelection
14833        } else if is_selection_reversed {
14834            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14835            SelectSyntaxNodeScrollBehavior::CursorTop
14836        } else {
14837            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14838            SelectSyntaxNodeScrollBehavior::CursorBottom
14839        };
14840
14841        self.select_syntax_node_history.push((
14842            old_selections,
14843            scroll_behavior,
14844            is_selection_reversed,
14845        ));
14846    }
14847
14848    pub fn select_smaller_syntax_node(
14849        &mut self,
14850        _: &SelectSmallerSyntaxNode,
14851        window: &mut Window,
14852        cx: &mut Context<Self>,
14853    ) {
14854        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14855
14856        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14857            self.select_syntax_node_history.pop()
14858        {
14859            if let Some(selection) = selections.last_mut() {
14860                selection.reversed = is_selection_reversed;
14861            }
14862
14863            self.select_syntax_node_history.disable_clearing = true;
14864            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14865                s.select(selections.to_vec());
14866            });
14867            self.select_syntax_node_history.disable_clearing = false;
14868
14869            match scroll_behavior {
14870                SelectSyntaxNodeScrollBehavior::CursorTop => {
14871                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14872                }
14873                SelectSyntaxNodeScrollBehavior::FitSelection => {
14874                    self.request_autoscroll(Autoscroll::fit(), cx);
14875                }
14876                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14877                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14878                }
14879            }
14880        }
14881    }
14882
14883    pub fn unwrap_syntax_node(
14884        &mut self,
14885        _: &UnwrapSyntaxNode,
14886        window: &mut Window,
14887        cx: &mut Context<Self>,
14888    ) {
14889        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14890
14891        let buffer = self.buffer.read(cx).snapshot(cx);
14892        let selections = self
14893            .selections
14894            .all::<usize>(cx)
14895            .into_iter()
14896            // subtracting the offset requires sorting
14897            .sorted_by_key(|i| i.start);
14898
14899        let full_edits = selections
14900            .into_iter()
14901            .filter_map(|selection| {
14902                // Only requires two branches once if-let-chains stabilize (#53667)
14903                let child = if !selection.is_empty() {
14904                    selection.range()
14905                } else if let Some((_, ancestor_range)) =
14906                    buffer.syntax_ancestor(selection.start..selection.end)
14907                {
14908                    match ancestor_range {
14909                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14910                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14911                    }
14912                } else {
14913                    selection.range()
14914                };
14915
14916                let mut parent = child.clone();
14917                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
14918                    parent = match ancestor_range {
14919                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14920                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14921                    };
14922                    if parent.start < child.start || parent.end > child.end {
14923                        break;
14924                    }
14925                }
14926
14927                if parent == child {
14928                    return None;
14929                }
14930                let text = buffer.text_for_range(child).collect::<String>();
14931                Some((selection.id, parent, text))
14932            })
14933            .collect::<Vec<_>>();
14934
14935        self.transact(window, cx, |this, window, cx| {
14936            this.buffer.update(cx, |buffer, cx| {
14937                buffer.edit(
14938                    full_edits
14939                        .iter()
14940                        .map(|(_, p, t)| (p.clone(), t.clone()))
14941                        .collect::<Vec<_>>(),
14942                    None,
14943                    cx,
14944                );
14945            });
14946            this.change_selections(Default::default(), window, cx, |s| {
14947                let mut offset = 0;
14948                let mut selections = vec![];
14949                for (id, parent, text) in full_edits {
14950                    let start = parent.start - offset;
14951                    offset += parent.len() - text.len();
14952                    selections.push(Selection {
14953                        id,
14954                        start,
14955                        end: start + text.len(),
14956                        reversed: false,
14957                        goal: Default::default(),
14958                    });
14959                }
14960                s.select(selections);
14961            });
14962        });
14963    }
14964
14965    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14966        if !EditorSettings::get_global(cx).gutter.runnables {
14967            self.clear_tasks();
14968            return Task::ready(());
14969        }
14970        let project = self.project().map(Entity::downgrade);
14971        let task_sources = self.lsp_task_sources(cx);
14972        let multi_buffer = self.buffer.downgrade();
14973        cx.spawn_in(window, async move |editor, cx| {
14974            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14975            let Some(project) = project.and_then(|p| p.upgrade()) else {
14976                return;
14977            };
14978            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14979                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14980            }) else {
14981                return;
14982            };
14983
14984            let hide_runnables = project
14985                .update(cx, |project, _| project.is_via_collab())
14986                .unwrap_or(true);
14987            if hide_runnables {
14988                return;
14989            }
14990            let new_rows =
14991                cx.background_spawn({
14992                    let snapshot = display_snapshot.clone();
14993                    async move {
14994                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14995                    }
14996                })
14997                    .await;
14998            let Ok(lsp_tasks) =
14999                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15000            else {
15001                return;
15002            };
15003            let lsp_tasks = lsp_tasks.await;
15004
15005            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15006                lsp_tasks
15007                    .into_iter()
15008                    .flat_map(|(kind, tasks)| {
15009                        tasks.into_iter().filter_map(move |(location, task)| {
15010                            Some((kind.clone(), location?, task))
15011                        })
15012                    })
15013                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15014                        let buffer = location.target.buffer;
15015                        let buffer_snapshot = buffer.read(cx).snapshot();
15016                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15017                            |(excerpt_id, snapshot, _)| {
15018                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15019                                    display_snapshot
15020                                        .buffer_snapshot
15021                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15022                                } else {
15023                                    None
15024                                }
15025                            },
15026                        );
15027                        if let Some(offset) = offset {
15028                            let task_buffer_range =
15029                                location.target.range.to_point(&buffer_snapshot);
15030                            let context_buffer_range =
15031                                task_buffer_range.to_offset(&buffer_snapshot);
15032                            let context_range = BufferOffset(context_buffer_range.start)
15033                                ..BufferOffset(context_buffer_range.end);
15034
15035                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15036                                .or_insert_with(|| RunnableTasks {
15037                                    templates: Vec::new(),
15038                                    offset,
15039                                    column: task_buffer_range.start.column,
15040                                    extra_variables: HashMap::default(),
15041                                    context_range,
15042                                })
15043                                .templates
15044                                .push((kind, task.original_task().clone()));
15045                        }
15046
15047                        acc
15048                    })
15049            }) else {
15050                return;
15051            };
15052
15053            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15054                buffer.language_settings(cx).tasks.prefer_lsp
15055            }) else {
15056                return;
15057            };
15058
15059            let rows = Self::runnable_rows(
15060                project,
15061                display_snapshot,
15062                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15063                new_rows,
15064                cx.clone(),
15065            )
15066            .await;
15067            editor
15068                .update(cx, |editor, _| {
15069                    editor.clear_tasks();
15070                    for (key, mut value) in rows {
15071                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15072                            value.templates.extend(lsp_tasks.templates);
15073                        }
15074
15075                        editor.insert_tasks(key, value);
15076                    }
15077                    for (key, value) in lsp_tasks_by_rows {
15078                        editor.insert_tasks(key, value);
15079                    }
15080                })
15081                .ok();
15082        })
15083    }
15084    fn fetch_runnable_ranges(
15085        snapshot: &DisplaySnapshot,
15086        range: Range<Anchor>,
15087    ) -> Vec<language::RunnableRange> {
15088        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15089    }
15090
15091    fn runnable_rows(
15092        project: Entity<Project>,
15093        snapshot: DisplaySnapshot,
15094        prefer_lsp: bool,
15095        runnable_ranges: Vec<RunnableRange>,
15096        cx: AsyncWindowContext,
15097    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15098        cx.spawn(async move |cx| {
15099            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15100            for mut runnable in runnable_ranges {
15101                let Some(tasks) = cx
15102                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15103                    .ok()
15104                else {
15105                    continue;
15106                };
15107                let mut tasks = tasks.await;
15108
15109                if prefer_lsp {
15110                    tasks.retain(|(task_kind, _)| {
15111                        !matches!(task_kind, TaskSourceKind::Language { .. })
15112                    });
15113                }
15114                if tasks.is_empty() {
15115                    continue;
15116                }
15117
15118                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15119                let Some(row) = snapshot
15120                    .buffer_snapshot
15121                    .buffer_line_for_row(MultiBufferRow(point.row))
15122                    .map(|(_, range)| range.start.row)
15123                else {
15124                    continue;
15125                };
15126
15127                let context_range =
15128                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15129                runnable_rows.push((
15130                    (runnable.buffer_id, row),
15131                    RunnableTasks {
15132                        templates: tasks,
15133                        offset: snapshot
15134                            .buffer_snapshot
15135                            .anchor_before(runnable.run_range.start),
15136                        context_range,
15137                        column: point.column,
15138                        extra_variables: runnable.extra_captures,
15139                    },
15140                ));
15141            }
15142            runnable_rows
15143        })
15144    }
15145
15146    fn templates_with_tags(
15147        project: &Entity<Project>,
15148        runnable: &mut Runnable,
15149        cx: &mut App,
15150    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15151        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15152            let (worktree_id, file) = project
15153                .buffer_for_id(runnable.buffer, cx)
15154                .and_then(|buffer| buffer.read(cx).file())
15155                .map(|file| (file.worktree_id(cx), file.clone()))
15156                .unzip();
15157
15158            (
15159                project.task_store().read(cx).task_inventory().cloned(),
15160                worktree_id,
15161                file,
15162            )
15163        });
15164
15165        let tags = mem::take(&mut runnable.tags);
15166        let language = runnable.language.clone();
15167        cx.spawn(async move |cx| {
15168            let mut templates_with_tags = Vec::new();
15169            if let Some(inventory) = inventory {
15170                for RunnableTag(tag) in tags {
15171                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15172                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15173                    }) else {
15174                        return templates_with_tags;
15175                    };
15176                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15177                        move |(_, template)| {
15178                            template.tags.iter().any(|source_tag| source_tag == &tag)
15179                        },
15180                    ));
15181                }
15182            }
15183            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15184
15185            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15186                // Strongest source wins; if we have worktree tag binding, prefer that to
15187                // global and language bindings;
15188                // if we have a global binding, prefer that to language binding.
15189                let first_mismatch = templates_with_tags
15190                    .iter()
15191                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15192                if let Some(index) = first_mismatch {
15193                    templates_with_tags.truncate(index);
15194                }
15195            }
15196
15197            templates_with_tags
15198        })
15199    }
15200
15201    pub fn move_to_enclosing_bracket(
15202        &mut self,
15203        _: &MoveToEnclosingBracket,
15204        window: &mut Window,
15205        cx: &mut Context<Self>,
15206    ) {
15207        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15208        self.change_selections(Default::default(), window, cx, |s| {
15209            s.move_offsets_with(|snapshot, selection| {
15210                let Some(enclosing_bracket_ranges) =
15211                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15212                else {
15213                    return;
15214                };
15215
15216                let mut best_length = usize::MAX;
15217                let mut best_inside = false;
15218                let mut best_in_bracket_range = false;
15219                let mut best_destination = None;
15220                for (open, close) in enclosing_bracket_ranges {
15221                    let close = close.to_inclusive();
15222                    let length = close.end() - open.start;
15223                    let inside = selection.start >= open.end && selection.end <= *close.start();
15224                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15225                        || close.contains(&selection.head());
15226
15227                    // If best is next to a bracket and current isn't, skip
15228                    if !in_bracket_range && best_in_bracket_range {
15229                        continue;
15230                    }
15231
15232                    // Prefer smaller lengths unless best is inside and current isn't
15233                    if length > best_length && (best_inside || !inside) {
15234                        continue;
15235                    }
15236
15237                    best_length = length;
15238                    best_inside = inside;
15239                    best_in_bracket_range = in_bracket_range;
15240                    best_destination = Some(
15241                        if close.contains(&selection.start) && close.contains(&selection.end) {
15242                            if inside { open.end } else { open.start }
15243                        } else if inside {
15244                            *close.start()
15245                        } else {
15246                            *close.end()
15247                        },
15248                    );
15249                }
15250
15251                if let Some(destination) = best_destination {
15252                    selection.collapse_to(destination, SelectionGoal::None);
15253                }
15254            })
15255        });
15256    }
15257
15258    pub fn undo_selection(
15259        &mut self,
15260        _: &UndoSelection,
15261        window: &mut Window,
15262        cx: &mut Context<Self>,
15263    ) {
15264        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15265        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15266            self.selection_history.mode = SelectionHistoryMode::Undoing;
15267            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15268                this.end_selection(window, cx);
15269                this.change_selections(
15270                    SelectionEffects::scroll(Autoscroll::newest()),
15271                    window,
15272                    cx,
15273                    |s| s.select_anchors(entry.selections.to_vec()),
15274                );
15275            });
15276            self.selection_history.mode = SelectionHistoryMode::Normal;
15277
15278            self.select_next_state = entry.select_next_state;
15279            self.select_prev_state = entry.select_prev_state;
15280            self.add_selections_state = entry.add_selections_state;
15281        }
15282    }
15283
15284    pub fn redo_selection(
15285        &mut self,
15286        _: &RedoSelection,
15287        window: &mut Window,
15288        cx: &mut Context<Self>,
15289    ) {
15290        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15291        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15292            self.selection_history.mode = SelectionHistoryMode::Redoing;
15293            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15294                this.end_selection(window, cx);
15295                this.change_selections(
15296                    SelectionEffects::scroll(Autoscroll::newest()),
15297                    window,
15298                    cx,
15299                    |s| s.select_anchors(entry.selections.to_vec()),
15300                );
15301            });
15302            self.selection_history.mode = SelectionHistoryMode::Normal;
15303
15304            self.select_next_state = entry.select_next_state;
15305            self.select_prev_state = entry.select_prev_state;
15306            self.add_selections_state = entry.add_selections_state;
15307        }
15308    }
15309
15310    pub fn expand_excerpts(
15311        &mut self,
15312        action: &ExpandExcerpts,
15313        _: &mut Window,
15314        cx: &mut Context<Self>,
15315    ) {
15316        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15317    }
15318
15319    pub fn expand_excerpts_down(
15320        &mut self,
15321        action: &ExpandExcerptsDown,
15322        _: &mut Window,
15323        cx: &mut Context<Self>,
15324    ) {
15325        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15326    }
15327
15328    pub fn expand_excerpts_up(
15329        &mut self,
15330        action: &ExpandExcerptsUp,
15331        _: &mut Window,
15332        cx: &mut Context<Self>,
15333    ) {
15334        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15335    }
15336
15337    pub fn expand_excerpts_for_direction(
15338        &mut self,
15339        lines: u32,
15340        direction: ExpandExcerptDirection,
15341
15342        cx: &mut Context<Self>,
15343    ) {
15344        let selections = self.selections.disjoint_anchors();
15345
15346        let lines = if lines == 0 {
15347            EditorSettings::get_global(cx).expand_excerpt_lines
15348        } else {
15349            lines
15350        };
15351
15352        self.buffer.update(cx, |buffer, cx| {
15353            let snapshot = buffer.snapshot(cx);
15354            let mut excerpt_ids = selections
15355                .iter()
15356                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15357                .collect::<Vec<_>>();
15358            excerpt_ids.sort();
15359            excerpt_ids.dedup();
15360            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15361        })
15362    }
15363
15364    pub fn expand_excerpt(
15365        &mut self,
15366        excerpt: ExcerptId,
15367        direction: ExpandExcerptDirection,
15368        window: &mut Window,
15369        cx: &mut Context<Self>,
15370    ) {
15371        let current_scroll_position = self.scroll_position(cx);
15372        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15373        let mut should_scroll_up = false;
15374
15375        if direction == ExpandExcerptDirection::Down {
15376            let multi_buffer = self.buffer.read(cx);
15377            let snapshot = multi_buffer.snapshot(cx);
15378            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15379                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15380                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15381            {
15382                let buffer_snapshot = buffer.read(cx).snapshot();
15383                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15384                let last_row = buffer_snapshot.max_point().row;
15385                let lines_below = last_row.saturating_sub(excerpt_end_row);
15386                should_scroll_up = lines_below >= lines_to_expand;
15387            }
15388        }
15389
15390        self.buffer.update(cx, |buffer, cx| {
15391            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15392        });
15393
15394        if should_scroll_up {
15395            let new_scroll_position =
15396                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15397            self.set_scroll_position(new_scroll_position, window, cx);
15398        }
15399    }
15400
15401    pub fn go_to_singleton_buffer_point(
15402        &mut self,
15403        point: Point,
15404        window: &mut Window,
15405        cx: &mut Context<Self>,
15406    ) {
15407        self.go_to_singleton_buffer_range(point..point, window, cx);
15408    }
15409
15410    pub fn go_to_singleton_buffer_range(
15411        &mut self,
15412        range: Range<Point>,
15413        window: &mut Window,
15414        cx: &mut Context<Self>,
15415    ) {
15416        let multibuffer = self.buffer().read(cx);
15417        let Some(buffer) = multibuffer.as_singleton() else {
15418            return;
15419        };
15420        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15421            return;
15422        };
15423        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15424            return;
15425        };
15426        self.change_selections(
15427            SelectionEffects::default().nav_history(true),
15428            window,
15429            cx,
15430            |s| s.select_anchor_ranges([start..end]),
15431        );
15432    }
15433
15434    pub fn go_to_diagnostic(
15435        &mut self,
15436        action: &GoToDiagnostic,
15437        window: &mut Window,
15438        cx: &mut Context<Self>,
15439    ) {
15440        if !self.diagnostics_enabled() {
15441            return;
15442        }
15443        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15444        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15445    }
15446
15447    pub fn go_to_prev_diagnostic(
15448        &mut self,
15449        action: &GoToPreviousDiagnostic,
15450        window: &mut Window,
15451        cx: &mut Context<Self>,
15452    ) {
15453        if !self.diagnostics_enabled() {
15454            return;
15455        }
15456        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15457        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15458    }
15459
15460    pub fn go_to_diagnostic_impl(
15461        &mut self,
15462        direction: Direction,
15463        severity: GoToDiagnosticSeverityFilter,
15464        window: &mut Window,
15465        cx: &mut Context<Self>,
15466    ) {
15467        let buffer = self.buffer.read(cx).snapshot(cx);
15468        let selection = self.selections.newest::<usize>(cx);
15469
15470        let mut active_group_id = None;
15471        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15472            && active_group.active_range.start.to_offset(&buffer) == selection.start
15473        {
15474            active_group_id = Some(active_group.group_id);
15475        }
15476
15477        fn filtered(
15478            snapshot: EditorSnapshot,
15479            severity: GoToDiagnosticSeverityFilter,
15480            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15481        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15482            diagnostics
15483                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15484                .filter(|entry| entry.range.start != entry.range.end)
15485                .filter(|entry| !entry.diagnostic.is_unnecessary)
15486                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15487        }
15488
15489        let snapshot = self.snapshot(window, cx);
15490        let before = filtered(
15491            snapshot.clone(),
15492            severity,
15493            buffer
15494                .diagnostics_in_range(0..selection.start)
15495                .filter(|entry| entry.range.start <= selection.start),
15496        );
15497        let after = filtered(
15498            snapshot,
15499            severity,
15500            buffer
15501                .diagnostics_in_range(selection.start..buffer.len())
15502                .filter(|entry| entry.range.start >= selection.start),
15503        );
15504
15505        let mut found: Option<DiagnosticEntry<usize>> = None;
15506        if direction == Direction::Prev {
15507            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15508            {
15509                for diagnostic in prev_diagnostics.into_iter().rev() {
15510                    if diagnostic.range.start != selection.start
15511                        || active_group_id
15512                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15513                    {
15514                        found = Some(diagnostic);
15515                        break 'outer;
15516                    }
15517                }
15518            }
15519        } else {
15520            for diagnostic in after.chain(before) {
15521                if diagnostic.range.start != selection.start
15522                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15523                {
15524                    found = Some(diagnostic);
15525                    break;
15526                }
15527            }
15528        }
15529        let Some(next_diagnostic) = found else {
15530            return;
15531        };
15532
15533        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15534        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15535            return;
15536        };
15537        self.change_selections(Default::default(), window, cx, |s| {
15538            s.select_ranges(vec![
15539                next_diagnostic.range.start..next_diagnostic.range.start,
15540            ])
15541        });
15542        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15543        self.refresh_edit_prediction(false, true, window, cx);
15544    }
15545
15546    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15547        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15548        let snapshot = self.snapshot(window, cx);
15549        let selection = self.selections.newest::<Point>(cx);
15550        self.go_to_hunk_before_or_after_position(
15551            &snapshot,
15552            selection.head(),
15553            Direction::Next,
15554            window,
15555            cx,
15556        );
15557    }
15558
15559    pub fn go_to_hunk_before_or_after_position(
15560        &mut self,
15561        snapshot: &EditorSnapshot,
15562        position: Point,
15563        direction: Direction,
15564        window: &mut Window,
15565        cx: &mut Context<Editor>,
15566    ) {
15567        let row = if direction == Direction::Next {
15568            self.hunk_after_position(snapshot, position)
15569                .map(|hunk| hunk.row_range.start)
15570        } else {
15571            self.hunk_before_position(snapshot, position)
15572        };
15573
15574        if let Some(row) = row {
15575            let destination = Point::new(row.0, 0);
15576            let autoscroll = Autoscroll::center();
15577
15578            self.unfold_ranges(&[destination..destination], false, false, cx);
15579            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15580                s.select_ranges([destination..destination]);
15581            });
15582        }
15583    }
15584
15585    fn hunk_after_position(
15586        &mut self,
15587        snapshot: &EditorSnapshot,
15588        position: Point,
15589    ) -> Option<MultiBufferDiffHunk> {
15590        snapshot
15591            .buffer_snapshot
15592            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15593            .find(|hunk| hunk.row_range.start.0 > position.row)
15594            .or_else(|| {
15595                snapshot
15596                    .buffer_snapshot
15597                    .diff_hunks_in_range(Point::zero()..position)
15598                    .find(|hunk| hunk.row_range.end.0 < position.row)
15599            })
15600    }
15601
15602    fn go_to_prev_hunk(
15603        &mut self,
15604        _: &GoToPreviousHunk,
15605        window: &mut Window,
15606        cx: &mut Context<Self>,
15607    ) {
15608        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15609        let snapshot = self.snapshot(window, cx);
15610        let selection = self.selections.newest::<Point>(cx);
15611        self.go_to_hunk_before_or_after_position(
15612            &snapshot,
15613            selection.head(),
15614            Direction::Prev,
15615            window,
15616            cx,
15617        );
15618    }
15619
15620    fn hunk_before_position(
15621        &mut self,
15622        snapshot: &EditorSnapshot,
15623        position: Point,
15624    ) -> Option<MultiBufferRow> {
15625        snapshot
15626            .buffer_snapshot
15627            .diff_hunk_before(position)
15628            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15629    }
15630
15631    fn go_to_next_change(
15632        &mut self,
15633        _: &GoToNextChange,
15634        window: &mut Window,
15635        cx: &mut Context<Self>,
15636    ) {
15637        if let Some(selections) = self
15638            .change_list
15639            .next_change(1, Direction::Next)
15640            .map(|s| s.to_vec())
15641        {
15642            self.change_selections(Default::default(), window, cx, |s| {
15643                let map = s.display_map();
15644                s.select_display_ranges(selections.iter().map(|a| {
15645                    let point = a.to_display_point(&map);
15646                    point..point
15647                }))
15648            })
15649        }
15650    }
15651
15652    fn go_to_previous_change(
15653        &mut self,
15654        _: &GoToPreviousChange,
15655        window: &mut Window,
15656        cx: &mut Context<Self>,
15657    ) {
15658        if let Some(selections) = self
15659            .change_list
15660            .next_change(1, Direction::Prev)
15661            .map(|s| s.to_vec())
15662        {
15663            self.change_selections(Default::default(), window, cx, |s| {
15664                let map = s.display_map();
15665                s.select_display_ranges(selections.iter().map(|a| {
15666                    let point = a.to_display_point(&map);
15667                    point..point
15668                }))
15669            })
15670        }
15671    }
15672
15673    fn go_to_line<T: 'static>(
15674        &mut self,
15675        position: Anchor,
15676        highlight_color: Option<Hsla>,
15677        window: &mut Window,
15678        cx: &mut Context<Self>,
15679    ) {
15680        let snapshot = self.snapshot(window, cx).display_snapshot;
15681        let position = position.to_point(&snapshot.buffer_snapshot);
15682        let start = snapshot
15683            .buffer_snapshot
15684            .clip_point(Point::new(position.row, 0), Bias::Left);
15685        let end = start + Point::new(1, 0);
15686        let start = snapshot.buffer_snapshot.anchor_before(start);
15687        let end = snapshot.buffer_snapshot.anchor_before(end);
15688
15689        self.highlight_rows::<T>(
15690            start..end,
15691            highlight_color
15692                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15693            Default::default(),
15694            cx,
15695        );
15696
15697        if self.buffer.read(cx).is_singleton() {
15698            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15699        }
15700    }
15701
15702    pub fn go_to_definition(
15703        &mut self,
15704        _: &GoToDefinition,
15705        window: &mut Window,
15706        cx: &mut Context<Self>,
15707    ) -> Task<Result<Navigated>> {
15708        let definition =
15709            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15710        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15711        cx.spawn_in(window, async move |editor, cx| {
15712            if definition.await? == Navigated::Yes {
15713                return Ok(Navigated::Yes);
15714            }
15715            match fallback_strategy {
15716                GoToDefinitionFallback::None => Ok(Navigated::No),
15717                GoToDefinitionFallback::FindAllReferences => {
15718                    match editor.update_in(cx, |editor, window, cx| {
15719                        editor.find_all_references(&FindAllReferences, window, cx)
15720                    })? {
15721                        Some(references) => references.await,
15722                        None => Ok(Navigated::No),
15723                    }
15724                }
15725            }
15726        })
15727    }
15728
15729    pub fn go_to_declaration(
15730        &mut self,
15731        _: &GoToDeclaration,
15732        window: &mut Window,
15733        cx: &mut Context<Self>,
15734    ) -> Task<Result<Navigated>> {
15735        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15736    }
15737
15738    pub fn go_to_declaration_split(
15739        &mut self,
15740        _: &GoToDeclaration,
15741        window: &mut Window,
15742        cx: &mut Context<Self>,
15743    ) -> Task<Result<Navigated>> {
15744        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15745    }
15746
15747    pub fn go_to_implementation(
15748        &mut self,
15749        _: &GoToImplementation,
15750        window: &mut Window,
15751        cx: &mut Context<Self>,
15752    ) -> Task<Result<Navigated>> {
15753        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15754    }
15755
15756    pub fn go_to_implementation_split(
15757        &mut self,
15758        _: &GoToImplementationSplit,
15759        window: &mut Window,
15760        cx: &mut Context<Self>,
15761    ) -> Task<Result<Navigated>> {
15762        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15763    }
15764
15765    pub fn go_to_type_definition(
15766        &mut self,
15767        _: &GoToTypeDefinition,
15768        window: &mut Window,
15769        cx: &mut Context<Self>,
15770    ) -> Task<Result<Navigated>> {
15771        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15772    }
15773
15774    pub fn go_to_definition_split(
15775        &mut self,
15776        _: &GoToDefinitionSplit,
15777        window: &mut Window,
15778        cx: &mut Context<Self>,
15779    ) -> Task<Result<Navigated>> {
15780        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15781    }
15782
15783    pub fn go_to_type_definition_split(
15784        &mut self,
15785        _: &GoToTypeDefinitionSplit,
15786        window: &mut Window,
15787        cx: &mut Context<Self>,
15788    ) -> Task<Result<Navigated>> {
15789        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15790    }
15791
15792    fn go_to_definition_of_kind(
15793        &mut self,
15794        kind: GotoDefinitionKind,
15795        split: bool,
15796        window: &mut Window,
15797        cx: &mut Context<Self>,
15798    ) -> Task<Result<Navigated>> {
15799        let Some(provider) = self.semantics_provider.clone() else {
15800            return Task::ready(Ok(Navigated::No));
15801        };
15802        let head = self.selections.newest::<usize>(cx).head();
15803        let buffer = self.buffer.read(cx);
15804        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15805            return Task::ready(Ok(Navigated::No));
15806        };
15807        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15808            return Task::ready(Ok(Navigated::No));
15809        };
15810
15811        cx.spawn_in(window, async move |editor, cx| {
15812            let Some(definitions) = definitions.await? else {
15813                return Ok(Navigated::No);
15814            };
15815            let navigated = editor
15816                .update_in(cx, |editor, window, cx| {
15817                    editor.navigate_to_hover_links(
15818                        Some(kind),
15819                        definitions
15820                            .into_iter()
15821                            .filter(|location| {
15822                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15823                            })
15824                            .map(HoverLink::Text)
15825                            .collect::<Vec<_>>(),
15826                        split,
15827                        window,
15828                        cx,
15829                    )
15830                })?
15831                .await?;
15832            anyhow::Ok(navigated)
15833        })
15834    }
15835
15836    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15837        let selection = self.selections.newest_anchor();
15838        let head = selection.head();
15839        let tail = selection.tail();
15840
15841        let Some((buffer, start_position)) =
15842            self.buffer.read(cx).text_anchor_for_position(head, cx)
15843        else {
15844            return;
15845        };
15846
15847        let end_position = if head != tail {
15848            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15849                return;
15850            };
15851            Some(pos)
15852        } else {
15853            None
15854        };
15855
15856        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15857            let url = if let Some(end_pos) = end_position {
15858                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15859            } else {
15860                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15861            };
15862
15863            if let Some(url) = url {
15864                editor.update(cx, |_, cx| {
15865                    cx.open_url(&url);
15866                })
15867            } else {
15868                Ok(())
15869            }
15870        });
15871
15872        url_finder.detach();
15873    }
15874
15875    pub fn open_selected_filename(
15876        &mut self,
15877        _: &OpenSelectedFilename,
15878        window: &mut Window,
15879        cx: &mut Context<Self>,
15880    ) {
15881        let Some(workspace) = self.workspace() else {
15882            return;
15883        };
15884
15885        let position = self.selections.newest_anchor().head();
15886
15887        let Some((buffer, buffer_position)) =
15888            self.buffer.read(cx).text_anchor_for_position(position, cx)
15889        else {
15890            return;
15891        };
15892
15893        let project = self.project.clone();
15894
15895        cx.spawn_in(window, async move |_, cx| {
15896            let result = find_file(&buffer, project, buffer_position, cx).await;
15897
15898            if let Some((_, path)) = result {
15899                workspace
15900                    .update_in(cx, |workspace, window, cx| {
15901                        workspace.open_resolved_path(path, window, cx)
15902                    })?
15903                    .await?;
15904            }
15905            anyhow::Ok(())
15906        })
15907        .detach();
15908    }
15909
15910    pub(crate) fn navigate_to_hover_links(
15911        &mut self,
15912        kind: Option<GotoDefinitionKind>,
15913        definitions: Vec<HoverLink>,
15914        split: bool,
15915        window: &mut Window,
15916        cx: &mut Context<Editor>,
15917    ) -> Task<Result<Navigated>> {
15918        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
15919        let mut first_url_or_file = None;
15920        let definitions: Vec<_> = definitions
15921            .into_iter()
15922            .filter_map(|def| match def {
15923                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
15924                HoverLink::InlayHint(lsp_location, server_id) => {
15925                    let computation =
15926                        self.compute_target_location(lsp_location, server_id, window, cx);
15927                    Some(cx.background_spawn(computation))
15928                }
15929                HoverLink::Url(url) => {
15930                    first_url_or_file = Some(Either::Left(url));
15931                    None
15932                }
15933                HoverLink::File(path) => {
15934                    first_url_or_file = Some(Either::Right(path));
15935                    None
15936                }
15937            })
15938            .collect();
15939
15940        let workspace = self.workspace();
15941
15942        cx.spawn_in(window, async move |editor, acx| {
15943            let mut locations: Vec<Location> = future::join_all(definitions)
15944                .await
15945                .into_iter()
15946                .filter_map(|location| location.transpose())
15947                .collect::<Result<_>>()
15948                .context("location tasks")?;
15949
15950            if locations.len() > 1 {
15951                let Some(workspace) = workspace else {
15952                    return Ok(Navigated::No);
15953                };
15954
15955                let tab_kind = match kind {
15956                    Some(GotoDefinitionKind::Implementation) => "Implementations",
15957                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
15958                    Some(GotoDefinitionKind::Declaration) => "Declarations",
15959                    Some(GotoDefinitionKind::Type) => "Types",
15960                };
15961                let title = editor
15962                    .update_in(acx, |_, _, cx| {
15963                        let target = locations
15964                            .iter()
15965                            .map(|location| {
15966                                location
15967                                    .buffer
15968                                    .read(cx)
15969                                    .text_for_range(location.range.clone())
15970                                    .collect::<String>()
15971                            })
15972                            .filter(|text| !text.contains('\n'))
15973                            .unique()
15974                            .take(3)
15975                            .join(", ");
15976                        if target.is_empty() {
15977                            tab_kind.to_owned()
15978                        } else {
15979                            format!("{tab_kind} for {target}")
15980                        }
15981                    })
15982                    .context("buffer title")?;
15983
15984                let opened = workspace
15985                    .update_in(acx, |workspace, window, cx| {
15986                        Self::open_locations_in_multibuffer(
15987                            workspace,
15988                            locations,
15989                            title,
15990                            split,
15991                            MultibufferSelectionMode::First,
15992                            window,
15993                            cx,
15994                        )
15995                    })
15996                    .is_ok();
15997
15998                anyhow::Ok(Navigated::from_bool(opened))
15999            } else if locations.is_empty() {
16000                // If there is one definition, just open it directly
16001                match first_url_or_file {
16002                    Some(Either::Left(url)) => {
16003                        acx.update(|_, cx| cx.open_url(&url))?;
16004                        Ok(Navigated::Yes)
16005                    }
16006                    Some(Either::Right(path)) => {
16007                        let Some(workspace) = workspace else {
16008                            return Ok(Navigated::No);
16009                        };
16010
16011                        workspace
16012                            .update_in(acx, |workspace, window, cx| {
16013                                workspace.open_resolved_path(path, window, cx)
16014                            })?
16015                            .await?;
16016                        Ok(Navigated::Yes)
16017                    }
16018                    None => Ok(Navigated::No),
16019                }
16020            } else {
16021                let Some(workspace) = workspace else {
16022                    return Ok(Navigated::No);
16023                };
16024
16025                let target = locations.pop().unwrap();
16026                editor.update_in(acx, |editor, window, cx| {
16027                    let pane = workspace.read(cx).active_pane().clone();
16028
16029                    let range = target.range.to_point(target.buffer.read(cx));
16030                    let range = editor.range_for_match(&range);
16031                    let range = collapse_multiline_range(range);
16032
16033                    if !split
16034                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16035                    {
16036                        editor.go_to_singleton_buffer_range(range, window, cx);
16037                    } else {
16038                        window.defer(cx, move |window, cx| {
16039                            let target_editor: Entity<Self> =
16040                                workspace.update(cx, |workspace, cx| {
16041                                    let pane = if split {
16042                                        workspace.adjacent_pane(window, cx)
16043                                    } else {
16044                                        workspace.active_pane().clone()
16045                                    };
16046
16047                                    workspace.open_project_item(
16048                                        pane,
16049                                        target.buffer.clone(),
16050                                        true,
16051                                        true,
16052                                        window,
16053                                        cx,
16054                                    )
16055                                });
16056                            target_editor.update(cx, |target_editor, cx| {
16057                                // When selecting a definition in a different buffer, disable the nav history
16058                                // to avoid creating a history entry at the previous cursor location.
16059                                pane.update(cx, |pane, _| pane.disable_history());
16060                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16061                                pane.update(cx, |pane, _| pane.enable_history());
16062                            });
16063                        });
16064                    }
16065                    Navigated::Yes
16066                })
16067            }
16068        })
16069    }
16070
16071    fn compute_target_location(
16072        &self,
16073        lsp_location: lsp::Location,
16074        server_id: LanguageServerId,
16075        window: &mut Window,
16076        cx: &mut Context<Self>,
16077    ) -> Task<anyhow::Result<Option<Location>>> {
16078        let Some(project) = self.project.clone() else {
16079            return Task::ready(Ok(None));
16080        };
16081
16082        cx.spawn_in(window, async move |editor, cx| {
16083            let location_task = editor.update(cx, |_, cx| {
16084                project.update(cx, |project, cx| {
16085                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16086                })
16087            })?;
16088            let location = Some({
16089                let target_buffer_handle = location_task.await.context("open local buffer")?;
16090                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16091                    let target_start = target_buffer
16092                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16093                    let target_end = target_buffer
16094                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16095                    target_buffer.anchor_after(target_start)
16096                        ..target_buffer.anchor_before(target_end)
16097                })?;
16098                Location {
16099                    buffer: target_buffer_handle,
16100                    range,
16101                }
16102            });
16103            Ok(location)
16104        })
16105    }
16106
16107    pub fn find_all_references(
16108        &mut self,
16109        _: &FindAllReferences,
16110        window: &mut Window,
16111        cx: &mut Context<Self>,
16112    ) -> Option<Task<Result<Navigated>>> {
16113        let selection = self.selections.newest::<usize>(cx);
16114        let multi_buffer = self.buffer.read(cx);
16115        let head = selection.head();
16116
16117        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16118        let head_anchor = multi_buffer_snapshot.anchor_at(
16119            head,
16120            if head < selection.tail() {
16121                Bias::Right
16122            } else {
16123                Bias::Left
16124            },
16125        );
16126
16127        match self
16128            .find_all_references_task_sources
16129            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16130        {
16131            Ok(_) => {
16132                log::info!(
16133                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16134                );
16135                return None;
16136            }
16137            Err(i) => {
16138                self.find_all_references_task_sources.insert(i, head_anchor);
16139            }
16140        }
16141
16142        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16143        let workspace = self.workspace()?;
16144        let project = workspace.read(cx).project().clone();
16145        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16146        Some(cx.spawn_in(window, async move |editor, cx| {
16147            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16148                if let Ok(i) = editor
16149                    .find_all_references_task_sources
16150                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16151                {
16152                    editor.find_all_references_task_sources.remove(i);
16153                }
16154            });
16155
16156            let Some(locations) = references.await? else {
16157                return anyhow::Ok(Navigated::No);
16158            };
16159            if locations.is_empty() {
16160                return anyhow::Ok(Navigated::No);
16161            }
16162
16163            workspace.update_in(cx, |workspace, window, cx| {
16164                let target = locations
16165                    .iter()
16166                    .map(|location| {
16167                        location
16168                            .buffer
16169                            .read(cx)
16170                            .text_for_range(location.range.clone())
16171                            .collect::<String>()
16172                    })
16173                    .filter(|text| !text.contains('\n'))
16174                    .unique()
16175                    .take(3)
16176                    .join(", ");
16177                let title = if target.is_empty() {
16178                    "References".to_owned()
16179                } else {
16180                    format!("References to {target}")
16181                };
16182                Self::open_locations_in_multibuffer(
16183                    workspace,
16184                    locations,
16185                    title,
16186                    false,
16187                    MultibufferSelectionMode::First,
16188                    window,
16189                    cx,
16190                );
16191                Navigated::Yes
16192            })
16193        }))
16194    }
16195
16196    /// Opens a multibuffer with the given project locations in it
16197    pub fn open_locations_in_multibuffer(
16198        workspace: &mut Workspace,
16199        mut locations: Vec<Location>,
16200        title: String,
16201        split: bool,
16202        multibuffer_selection_mode: MultibufferSelectionMode,
16203        window: &mut Window,
16204        cx: &mut Context<Workspace>,
16205    ) {
16206        if locations.is_empty() {
16207            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16208            return;
16209        }
16210
16211        // If there are multiple definitions, open them in a multibuffer
16212        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16213        let mut locations = locations.into_iter().peekable();
16214        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16215        let capability = workspace.project().read(cx).capability();
16216
16217        let excerpt_buffer = cx.new(|cx| {
16218            let mut multibuffer = MultiBuffer::new(capability);
16219            while let Some(location) = locations.next() {
16220                let buffer = location.buffer.read(cx);
16221                let mut ranges_for_buffer = Vec::new();
16222                let range = location.range.to_point(buffer);
16223                ranges_for_buffer.push(range.clone());
16224
16225                while let Some(next_location) = locations.peek() {
16226                    if next_location.buffer == location.buffer {
16227                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16228                        locations.next();
16229                    } else {
16230                        break;
16231                    }
16232                }
16233
16234                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16235                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16236                    PathKey::for_buffer(&location.buffer, cx),
16237                    location.buffer.clone(),
16238                    ranges_for_buffer,
16239                    multibuffer_context_lines(cx),
16240                    cx,
16241                );
16242                ranges.extend(new_ranges)
16243            }
16244
16245            multibuffer.with_title(title)
16246        });
16247
16248        let editor = cx.new(|cx| {
16249            Editor::for_multibuffer(
16250                excerpt_buffer,
16251                Some(workspace.project().clone()),
16252                window,
16253                cx,
16254            )
16255        });
16256        editor.update(cx, |editor, cx| {
16257            match multibuffer_selection_mode {
16258                MultibufferSelectionMode::First => {
16259                    if let Some(first_range) = ranges.first() {
16260                        editor.change_selections(
16261                            SelectionEffects::no_scroll(),
16262                            window,
16263                            cx,
16264                            |selections| {
16265                                selections.clear_disjoint();
16266                                selections
16267                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16268                            },
16269                        );
16270                    }
16271                    editor.highlight_background::<Self>(
16272                        &ranges,
16273                        |theme| theme.colors().editor_highlighted_line_background,
16274                        cx,
16275                    );
16276                }
16277                MultibufferSelectionMode::All => {
16278                    editor.change_selections(
16279                        SelectionEffects::no_scroll(),
16280                        window,
16281                        cx,
16282                        |selections| {
16283                            selections.clear_disjoint();
16284                            selections.select_anchor_ranges(ranges);
16285                        },
16286                    );
16287                }
16288            }
16289            editor.register_buffers_with_language_servers(cx);
16290        });
16291
16292        let item = Box::new(editor);
16293        let item_id = item.item_id();
16294
16295        if split {
16296            workspace.split_item(SplitDirection::Right, item, window, cx);
16297        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16298            let (preview_item_id, preview_item_idx) =
16299                workspace.active_pane().read_with(cx, |pane, _| {
16300                    (pane.preview_item_id(), pane.preview_item_idx())
16301                });
16302
16303            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16304
16305            if let Some(preview_item_id) = preview_item_id {
16306                workspace.active_pane().update(cx, |pane, cx| {
16307                    pane.remove_item(preview_item_id, false, false, window, cx);
16308                });
16309            }
16310        } else {
16311            workspace.add_item_to_active_pane(item, None, true, window, cx);
16312        }
16313        workspace.active_pane().update(cx, |pane, cx| {
16314            pane.set_preview_item_id(Some(item_id), cx);
16315        });
16316    }
16317
16318    pub fn rename(
16319        &mut self,
16320        _: &Rename,
16321        window: &mut Window,
16322        cx: &mut Context<Self>,
16323    ) -> Option<Task<Result<()>>> {
16324        use language::ToOffset as _;
16325
16326        let provider = self.semantics_provider.clone()?;
16327        let selection = self.selections.newest_anchor().clone();
16328        let (cursor_buffer, cursor_buffer_position) = self
16329            .buffer
16330            .read(cx)
16331            .text_anchor_for_position(selection.head(), cx)?;
16332        let (tail_buffer, cursor_buffer_position_end) = self
16333            .buffer
16334            .read(cx)
16335            .text_anchor_for_position(selection.tail(), cx)?;
16336        if tail_buffer != cursor_buffer {
16337            return None;
16338        }
16339
16340        let snapshot = cursor_buffer.read(cx).snapshot();
16341        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16342        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16343        let prepare_rename = provider
16344            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16345            .unwrap_or_else(|| Task::ready(Ok(None)));
16346        drop(snapshot);
16347
16348        Some(cx.spawn_in(window, async move |this, cx| {
16349            let rename_range = if let Some(range) = prepare_rename.await? {
16350                Some(range)
16351            } else {
16352                this.update(cx, |this, cx| {
16353                    let buffer = this.buffer.read(cx).snapshot(cx);
16354                    let mut buffer_highlights = this
16355                        .document_highlights_for_position(selection.head(), &buffer)
16356                        .filter(|highlight| {
16357                            highlight.start.excerpt_id == selection.head().excerpt_id
16358                                && highlight.end.excerpt_id == selection.head().excerpt_id
16359                        });
16360                    buffer_highlights
16361                        .next()
16362                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16363                })?
16364            };
16365            if let Some(rename_range) = rename_range {
16366                this.update_in(cx, |this, window, cx| {
16367                    let snapshot = cursor_buffer.read(cx).snapshot();
16368                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16369                    let cursor_offset_in_rename_range =
16370                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16371                    let cursor_offset_in_rename_range_end =
16372                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16373
16374                    this.take_rename(false, window, cx);
16375                    let buffer = this.buffer.read(cx).read(cx);
16376                    let cursor_offset = selection.head().to_offset(&buffer);
16377                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16378                    let rename_end = rename_start + rename_buffer_range.len();
16379                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16380                    let mut old_highlight_id = None;
16381                    let old_name: Arc<str> = buffer
16382                        .chunks(rename_start..rename_end, true)
16383                        .map(|chunk| {
16384                            if old_highlight_id.is_none() {
16385                                old_highlight_id = chunk.syntax_highlight_id;
16386                            }
16387                            chunk.text
16388                        })
16389                        .collect::<String>()
16390                        .into();
16391
16392                    drop(buffer);
16393
16394                    // Position the selection in the rename editor so that it matches the current selection.
16395                    this.show_local_selections = false;
16396                    let rename_editor = cx.new(|cx| {
16397                        let mut editor = Editor::single_line(window, cx);
16398                        editor.buffer.update(cx, |buffer, cx| {
16399                            buffer.edit([(0..0, old_name.clone())], None, cx)
16400                        });
16401                        let rename_selection_range = match cursor_offset_in_rename_range
16402                            .cmp(&cursor_offset_in_rename_range_end)
16403                        {
16404                            Ordering::Equal => {
16405                                editor.select_all(&SelectAll, window, cx);
16406                                return editor;
16407                            }
16408                            Ordering::Less => {
16409                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16410                            }
16411                            Ordering::Greater => {
16412                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16413                            }
16414                        };
16415                        if rename_selection_range.end > old_name.len() {
16416                            editor.select_all(&SelectAll, window, cx);
16417                        } else {
16418                            editor.change_selections(Default::default(), window, cx, |s| {
16419                                s.select_ranges([rename_selection_range]);
16420                            });
16421                        }
16422                        editor
16423                    });
16424                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16425                        if e == &EditorEvent::Focused {
16426                            cx.emit(EditorEvent::FocusedIn)
16427                        }
16428                    })
16429                    .detach();
16430
16431                    let write_highlights =
16432                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16433                    let read_highlights =
16434                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16435                    let ranges = write_highlights
16436                        .iter()
16437                        .flat_map(|(_, ranges)| ranges.iter())
16438                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16439                        .cloned()
16440                        .collect();
16441
16442                    this.highlight_text::<Rename>(
16443                        ranges,
16444                        HighlightStyle {
16445                            fade_out: Some(0.6),
16446                            ..Default::default()
16447                        },
16448                        cx,
16449                    );
16450                    let rename_focus_handle = rename_editor.focus_handle(cx);
16451                    window.focus(&rename_focus_handle);
16452                    let block_id = this.insert_blocks(
16453                        [BlockProperties {
16454                            style: BlockStyle::Flex,
16455                            placement: BlockPlacement::Below(range.start),
16456                            height: Some(1),
16457                            render: Arc::new({
16458                                let rename_editor = rename_editor.clone();
16459                                move |cx: &mut BlockContext| {
16460                                    let mut text_style = cx.editor_style.text.clone();
16461                                    if let Some(highlight_style) = old_highlight_id
16462                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16463                                    {
16464                                        text_style = text_style.highlight(highlight_style);
16465                                    }
16466                                    div()
16467                                        .block_mouse_except_scroll()
16468                                        .pl(cx.anchor_x)
16469                                        .child(EditorElement::new(
16470                                            &rename_editor,
16471                                            EditorStyle {
16472                                                background: cx.theme().system().transparent,
16473                                                local_player: cx.editor_style.local_player,
16474                                                text: text_style,
16475                                                scrollbar_width: cx.editor_style.scrollbar_width,
16476                                                syntax: cx.editor_style.syntax.clone(),
16477                                                status: cx.editor_style.status.clone(),
16478                                                inlay_hints_style: HighlightStyle {
16479                                                    font_weight: Some(FontWeight::BOLD),
16480                                                    ..make_inlay_hints_style(cx.app)
16481                                                },
16482                                                edit_prediction_styles: make_suggestion_styles(
16483                                                    cx.app,
16484                                                ),
16485                                                ..EditorStyle::default()
16486                                            },
16487                                        ))
16488                                        .into_any_element()
16489                                }
16490                            }),
16491                            priority: 0,
16492                        }],
16493                        Some(Autoscroll::fit()),
16494                        cx,
16495                    )[0];
16496                    this.pending_rename = Some(RenameState {
16497                        range,
16498                        old_name,
16499                        editor: rename_editor,
16500                        block_id,
16501                    });
16502                })?;
16503            }
16504
16505            Ok(())
16506        }))
16507    }
16508
16509    pub fn confirm_rename(
16510        &mut self,
16511        _: &ConfirmRename,
16512        window: &mut Window,
16513        cx: &mut Context<Self>,
16514    ) -> Option<Task<Result<()>>> {
16515        let rename = self.take_rename(false, window, cx)?;
16516        let workspace = self.workspace()?.downgrade();
16517        let (buffer, start) = self
16518            .buffer
16519            .read(cx)
16520            .text_anchor_for_position(rename.range.start, cx)?;
16521        let (end_buffer, _) = self
16522            .buffer
16523            .read(cx)
16524            .text_anchor_for_position(rename.range.end, cx)?;
16525        if buffer != end_buffer {
16526            return None;
16527        }
16528
16529        let old_name = rename.old_name;
16530        let new_name = rename.editor.read(cx).text(cx);
16531
16532        let rename = self.semantics_provider.as_ref()?.perform_rename(
16533            &buffer,
16534            start,
16535            new_name.clone(),
16536            cx,
16537        )?;
16538
16539        Some(cx.spawn_in(window, async move |editor, cx| {
16540            let project_transaction = rename.await?;
16541            Self::open_project_transaction(
16542                &editor,
16543                workspace,
16544                project_transaction,
16545                format!("Rename: {}{}", old_name, new_name),
16546                cx,
16547            )
16548            .await?;
16549
16550            editor.update(cx, |editor, cx| {
16551                editor.refresh_document_highlights(cx);
16552            })?;
16553            Ok(())
16554        }))
16555    }
16556
16557    fn take_rename(
16558        &mut self,
16559        moving_cursor: bool,
16560        window: &mut Window,
16561        cx: &mut Context<Self>,
16562    ) -> Option<RenameState> {
16563        let rename = self.pending_rename.take()?;
16564        if rename.editor.focus_handle(cx).is_focused(window) {
16565            window.focus(&self.focus_handle);
16566        }
16567
16568        self.remove_blocks(
16569            [rename.block_id].into_iter().collect(),
16570            Some(Autoscroll::fit()),
16571            cx,
16572        );
16573        self.clear_highlights::<Rename>(cx);
16574        self.show_local_selections = true;
16575
16576        if moving_cursor {
16577            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16578                editor.selections.newest::<usize>(cx).head()
16579            });
16580
16581            // Update the selection to match the position of the selection inside
16582            // the rename editor.
16583            let snapshot = self.buffer.read(cx).read(cx);
16584            let rename_range = rename.range.to_offset(&snapshot);
16585            let cursor_in_editor = snapshot
16586                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16587                .min(rename_range.end);
16588            drop(snapshot);
16589
16590            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16591                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16592            });
16593        } else {
16594            self.refresh_document_highlights(cx);
16595        }
16596
16597        Some(rename)
16598    }
16599
16600    pub fn pending_rename(&self) -> Option<&RenameState> {
16601        self.pending_rename.as_ref()
16602    }
16603
16604    fn format(
16605        &mut self,
16606        _: &Format,
16607        window: &mut Window,
16608        cx: &mut Context<Self>,
16609    ) -> Option<Task<Result<()>>> {
16610        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16611
16612        let project = match &self.project {
16613            Some(project) => project.clone(),
16614            None => return None,
16615        };
16616
16617        Some(self.perform_format(
16618            project,
16619            FormatTrigger::Manual,
16620            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16621            window,
16622            cx,
16623        ))
16624    }
16625
16626    fn format_selections(
16627        &mut self,
16628        _: &FormatSelections,
16629        window: &mut Window,
16630        cx: &mut Context<Self>,
16631    ) -> Option<Task<Result<()>>> {
16632        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16633
16634        let project = match &self.project {
16635            Some(project) => project.clone(),
16636            None => return None,
16637        };
16638
16639        let ranges = self
16640            .selections
16641            .all_adjusted(cx)
16642            .into_iter()
16643            .map(|selection| selection.range())
16644            .collect_vec();
16645
16646        Some(self.perform_format(
16647            project,
16648            FormatTrigger::Manual,
16649            FormatTarget::Ranges(ranges),
16650            window,
16651            cx,
16652        ))
16653    }
16654
16655    fn perform_format(
16656        &mut self,
16657        project: Entity<Project>,
16658        trigger: FormatTrigger,
16659        target: FormatTarget,
16660        window: &mut Window,
16661        cx: &mut Context<Self>,
16662    ) -> Task<Result<()>> {
16663        let buffer = self.buffer.clone();
16664        let (buffers, target) = match target {
16665            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16666            FormatTarget::Ranges(selection_ranges) => {
16667                let multi_buffer = buffer.read(cx);
16668                let snapshot = multi_buffer.read(cx);
16669                let mut buffers = HashSet::default();
16670                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16671                    BTreeMap::new();
16672                for selection_range in selection_ranges {
16673                    for (buffer, buffer_range, _) in
16674                        snapshot.range_to_buffer_ranges(selection_range)
16675                    {
16676                        let buffer_id = buffer.remote_id();
16677                        let start = buffer.anchor_before(buffer_range.start);
16678                        let end = buffer.anchor_after(buffer_range.end);
16679                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16680                        buffer_id_to_ranges
16681                            .entry(buffer_id)
16682                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16683                            .or_insert_with(|| vec![start..end]);
16684                    }
16685                }
16686                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16687            }
16688        };
16689
16690        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16691        let selections_prev = transaction_id_prev
16692            .and_then(|transaction_id_prev| {
16693                // default to selections as they were after the last edit, if we have them,
16694                // instead of how they are now.
16695                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16696                // will take you back to where you made the last edit, instead of staying where you scrolled
16697                self.selection_history
16698                    .transaction(transaction_id_prev)
16699                    .map(|t| t.0.clone())
16700            })
16701            .unwrap_or_else(|| self.selections.disjoint_anchors());
16702
16703        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16704        let format = project.update(cx, |project, cx| {
16705            project.format(buffers, target, true, trigger, cx)
16706        });
16707
16708        cx.spawn_in(window, async move |editor, cx| {
16709            let transaction = futures::select_biased! {
16710                transaction = format.log_err().fuse() => transaction,
16711                () = timeout => {
16712                    log::warn!("timed out waiting for formatting");
16713                    None
16714                }
16715            };
16716
16717            buffer
16718                .update(cx, |buffer, cx| {
16719                    if let Some(transaction) = transaction
16720                        && !buffer.is_singleton()
16721                    {
16722                        buffer.push_transaction(&transaction.0, cx);
16723                    }
16724                    cx.notify();
16725                })
16726                .ok();
16727
16728            if let Some(transaction_id_now) =
16729                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16730            {
16731                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16732                if has_new_transaction {
16733                    _ = editor.update(cx, |editor, _| {
16734                        editor
16735                            .selection_history
16736                            .insert_transaction(transaction_id_now, selections_prev);
16737                    });
16738                }
16739            }
16740
16741            Ok(())
16742        })
16743    }
16744
16745    fn organize_imports(
16746        &mut self,
16747        _: &OrganizeImports,
16748        window: &mut Window,
16749        cx: &mut Context<Self>,
16750    ) -> Option<Task<Result<()>>> {
16751        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16752        let project = match &self.project {
16753            Some(project) => project.clone(),
16754            None => return None,
16755        };
16756        Some(self.perform_code_action_kind(
16757            project,
16758            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16759            window,
16760            cx,
16761        ))
16762    }
16763
16764    fn perform_code_action_kind(
16765        &mut self,
16766        project: Entity<Project>,
16767        kind: CodeActionKind,
16768        window: &mut Window,
16769        cx: &mut Context<Self>,
16770    ) -> Task<Result<()>> {
16771        let buffer = self.buffer.clone();
16772        let buffers = buffer.read(cx).all_buffers();
16773        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16774        let apply_action = project.update(cx, |project, cx| {
16775            project.apply_code_action_kind(buffers, kind, true, cx)
16776        });
16777        cx.spawn_in(window, async move |_, cx| {
16778            let transaction = futures::select_biased! {
16779                () = timeout => {
16780                    log::warn!("timed out waiting for executing code action");
16781                    None
16782                }
16783                transaction = apply_action.log_err().fuse() => transaction,
16784            };
16785            buffer
16786                .update(cx, |buffer, cx| {
16787                    // check if we need this
16788                    if let Some(transaction) = transaction
16789                        && !buffer.is_singleton()
16790                    {
16791                        buffer.push_transaction(&transaction.0, cx);
16792                    }
16793                    cx.notify();
16794                })
16795                .ok();
16796            Ok(())
16797        })
16798    }
16799
16800    pub fn restart_language_server(
16801        &mut self,
16802        _: &RestartLanguageServer,
16803        _: &mut Window,
16804        cx: &mut Context<Self>,
16805    ) {
16806        if let Some(project) = self.project.clone() {
16807            self.buffer.update(cx, |multi_buffer, cx| {
16808                project.update(cx, |project, cx| {
16809                    project.restart_language_servers_for_buffers(
16810                        multi_buffer.all_buffers().into_iter().collect(),
16811                        HashSet::default(),
16812                        cx,
16813                    );
16814                });
16815            })
16816        }
16817    }
16818
16819    pub fn stop_language_server(
16820        &mut self,
16821        _: &StopLanguageServer,
16822        _: &mut Window,
16823        cx: &mut Context<Self>,
16824    ) {
16825        if let Some(project) = self.project.clone() {
16826            self.buffer.update(cx, |multi_buffer, cx| {
16827                project.update(cx, |project, cx| {
16828                    project.stop_language_servers_for_buffers(
16829                        multi_buffer.all_buffers().into_iter().collect(),
16830                        HashSet::default(),
16831                        cx,
16832                    );
16833                    cx.emit(project::Event::RefreshInlayHints);
16834                });
16835            });
16836        }
16837    }
16838
16839    fn cancel_language_server_work(
16840        workspace: &mut Workspace,
16841        _: &actions::CancelLanguageServerWork,
16842        _: &mut Window,
16843        cx: &mut Context<Workspace>,
16844    ) {
16845        let project = workspace.project();
16846        let buffers = workspace
16847            .active_item(cx)
16848            .and_then(|item| item.act_as::<Editor>(cx))
16849            .map_or(HashSet::default(), |editor| {
16850                editor.read(cx).buffer.read(cx).all_buffers()
16851            });
16852        project.update(cx, |project, cx| {
16853            project.cancel_language_server_work_for_buffers(buffers, cx);
16854        });
16855    }
16856
16857    fn show_character_palette(
16858        &mut self,
16859        _: &ShowCharacterPalette,
16860        window: &mut Window,
16861        _: &mut Context<Self>,
16862    ) {
16863        window.show_character_palette();
16864    }
16865
16866    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16867        if !self.diagnostics_enabled() {
16868            return;
16869        }
16870
16871        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16872            let buffer = self.buffer.read(cx).snapshot(cx);
16873            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16874            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16875            let is_valid = buffer
16876                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16877                .any(|entry| {
16878                    entry.diagnostic.is_primary
16879                        && !entry.range.is_empty()
16880                        && entry.range.start == primary_range_start
16881                        && entry.diagnostic.message == active_diagnostics.active_message
16882                });
16883
16884            if !is_valid {
16885                self.dismiss_diagnostics(cx);
16886            }
16887        }
16888    }
16889
16890    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16891        match &self.active_diagnostics {
16892            ActiveDiagnostic::Group(group) => Some(group),
16893            _ => None,
16894        }
16895    }
16896
16897    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16898        if !self.diagnostics_enabled() {
16899            return;
16900        }
16901        self.dismiss_diagnostics(cx);
16902        self.active_diagnostics = ActiveDiagnostic::All;
16903    }
16904
16905    fn activate_diagnostics(
16906        &mut self,
16907        buffer_id: BufferId,
16908        diagnostic: DiagnosticEntry<usize>,
16909        window: &mut Window,
16910        cx: &mut Context<Self>,
16911    ) {
16912        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16913            return;
16914        }
16915        self.dismiss_diagnostics(cx);
16916        let snapshot = self.snapshot(window, cx);
16917        let buffer = self.buffer.read(cx).snapshot(cx);
16918        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16919            return;
16920        };
16921
16922        let diagnostic_group = buffer
16923            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16924            .collect::<Vec<_>>();
16925
16926        let blocks =
16927            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16928
16929        let blocks = self.display_map.update(cx, |display_map, cx| {
16930            display_map.insert_blocks(blocks, cx).into_iter().collect()
16931        });
16932        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16933            active_range: buffer.anchor_before(diagnostic.range.start)
16934                ..buffer.anchor_after(diagnostic.range.end),
16935            active_message: diagnostic.diagnostic.message.clone(),
16936            group_id: diagnostic.diagnostic.group_id,
16937            blocks,
16938        });
16939        cx.notify();
16940    }
16941
16942    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16943        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16944            return;
16945        };
16946
16947        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16948        if let ActiveDiagnostic::Group(group) = prev {
16949            self.display_map.update(cx, |display_map, cx| {
16950                display_map.remove_blocks(group.blocks, cx);
16951            });
16952            cx.notify();
16953        }
16954    }
16955
16956    /// Disable inline diagnostics rendering for this editor.
16957    pub fn disable_inline_diagnostics(&mut self) {
16958        self.inline_diagnostics_enabled = false;
16959        self.inline_diagnostics_update = Task::ready(());
16960        self.inline_diagnostics.clear();
16961    }
16962
16963    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16964        self.diagnostics_enabled = false;
16965        self.dismiss_diagnostics(cx);
16966        self.inline_diagnostics_update = Task::ready(());
16967        self.inline_diagnostics.clear();
16968    }
16969
16970    pub fn diagnostics_enabled(&self) -> bool {
16971        self.diagnostics_enabled && self.mode.is_full()
16972    }
16973
16974    pub fn inline_diagnostics_enabled(&self) -> bool {
16975        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16976    }
16977
16978    pub fn show_inline_diagnostics(&self) -> bool {
16979        self.show_inline_diagnostics
16980    }
16981
16982    pub fn toggle_inline_diagnostics(
16983        &mut self,
16984        _: &ToggleInlineDiagnostics,
16985        window: &mut Window,
16986        cx: &mut Context<Editor>,
16987    ) {
16988        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16989        self.refresh_inline_diagnostics(false, window, cx);
16990    }
16991
16992    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16993        self.diagnostics_max_severity = severity;
16994        self.display_map.update(cx, |display_map, _| {
16995            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16996        });
16997    }
16998
16999    pub fn toggle_diagnostics(
17000        &mut self,
17001        _: &ToggleDiagnostics,
17002        window: &mut Window,
17003        cx: &mut Context<Editor>,
17004    ) {
17005        if !self.diagnostics_enabled() {
17006            return;
17007        }
17008
17009        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17010            EditorSettings::get_global(cx)
17011                .diagnostics_max_severity
17012                .filter(|severity| severity != &DiagnosticSeverity::Off)
17013                .unwrap_or(DiagnosticSeverity::Hint)
17014        } else {
17015            DiagnosticSeverity::Off
17016        };
17017        self.set_max_diagnostics_severity(new_severity, cx);
17018        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17019            self.active_diagnostics = ActiveDiagnostic::None;
17020            self.inline_diagnostics_update = Task::ready(());
17021            self.inline_diagnostics.clear();
17022        } else {
17023            self.refresh_inline_diagnostics(false, window, cx);
17024        }
17025
17026        cx.notify();
17027    }
17028
17029    pub fn toggle_minimap(
17030        &mut self,
17031        _: &ToggleMinimap,
17032        window: &mut Window,
17033        cx: &mut Context<Editor>,
17034    ) {
17035        if self.supports_minimap(cx) {
17036            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17037        }
17038    }
17039
17040    fn refresh_inline_diagnostics(
17041        &mut self,
17042        debounce: bool,
17043        window: &mut Window,
17044        cx: &mut Context<Self>,
17045    ) {
17046        let max_severity = ProjectSettings::get_global(cx)
17047            .diagnostics
17048            .inline
17049            .max_severity
17050            .unwrap_or(self.diagnostics_max_severity);
17051
17052        if !self.inline_diagnostics_enabled()
17053            || !self.show_inline_diagnostics
17054            || max_severity == DiagnosticSeverity::Off
17055        {
17056            self.inline_diagnostics_update = Task::ready(());
17057            self.inline_diagnostics.clear();
17058            return;
17059        }
17060
17061        let debounce_ms = ProjectSettings::get_global(cx)
17062            .diagnostics
17063            .inline
17064            .update_debounce_ms;
17065        let debounce = if debounce && debounce_ms > 0 {
17066            Some(Duration::from_millis(debounce_ms))
17067        } else {
17068            None
17069        };
17070        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17071            if let Some(debounce) = debounce {
17072                cx.background_executor().timer(debounce).await;
17073            }
17074            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17075                editor
17076                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17077                    .ok()
17078            }) else {
17079                return;
17080            };
17081
17082            let new_inline_diagnostics = cx
17083                .background_spawn(async move {
17084                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17085                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17086                        let message = diagnostic_entry
17087                            .diagnostic
17088                            .message
17089                            .split_once('\n')
17090                            .map(|(line, _)| line)
17091                            .map(SharedString::new)
17092                            .unwrap_or_else(|| {
17093                                SharedString::from(diagnostic_entry.diagnostic.message)
17094                            });
17095                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17096                        let (Ok(i) | Err(i)) = inline_diagnostics
17097                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17098                        inline_diagnostics.insert(
17099                            i,
17100                            (
17101                                start_anchor,
17102                                InlineDiagnostic {
17103                                    message,
17104                                    group_id: diagnostic_entry.diagnostic.group_id,
17105                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17106                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17107                                    severity: diagnostic_entry.diagnostic.severity,
17108                                },
17109                            ),
17110                        );
17111                    }
17112                    inline_diagnostics
17113                })
17114                .await;
17115
17116            editor
17117                .update(cx, |editor, cx| {
17118                    editor.inline_diagnostics = new_inline_diagnostics;
17119                    cx.notify();
17120                })
17121                .ok();
17122        });
17123    }
17124
17125    fn pull_diagnostics(
17126        &mut self,
17127        buffer_id: Option<BufferId>,
17128        window: &Window,
17129        cx: &mut Context<Self>,
17130    ) -> Option<()> {
17131        if !self.mode().is_full() {
17132            return None;
17133        }
17134        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17135            .diagnostics
17136            .lsp_pull_diagnostics;
17137        if !pull_diagnostics_settings.enabled {
17138            return None;
17139        }
17140        let project = self.project()?.downgrade();
17141        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17142        let mut buffers = self.buffer.read(cx).all_buffers();
17143        if let Some(buffer_id) = buffer_id {
17144            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17145        }
17146
17147        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17148            cx.background_executor().timer(debounce).await;
17149
17150            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17151                buffers
17152                    .into_iter()
17153                    .filter_map(|buffer| {
17154                        project
17155                            .update(cx, |project, cx| {
17156                                project.lsp_store().update(cx, |lsp_store, cx| {
17157                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17158                                })
17159                            })
17160                            .ok()
17161                    })
17162                    .collect::<FuturesUnordered<_>>()
17163            }) else {
17164                return;
17165            };
17166
17167            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17168                match pull_task {
17169                    Ok(()) => {
17170                        if editor
17171                            .update_in(cx, |editor, window, cx| {
17172                                editor.update_diagnostics_state(window, cx);
17173                            })
17174                            .is_err()
17175                        {
17176                            return;
17177                        }
17178                    }
17179                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17180                }
17181            }
17182        });
17183
17184        Some(())
17185    }
17186
17187    pub fn set_selections_from_remote(
17188        &mut self,
17189        selections: Vec<Selection<Anchor>>,
17190        pending_selection: Option<Selection<Anchor>>,
17191        window: &mut Window,
17192        cx: &mut Context<Self>,
17193    ) {
17194        let old_cursor_position = self.selections.newest_anchor().head();
17195        self.selections.change_with(cx, |s| {
17196            s.select_anchors(selections);
17197            if let Some(pending_selection) = pending_selection {
17198                s.set_pending(pending_selection, SelectMode::Character);
17199            } else {
17200                s.clear_pending();
17201            }
17202        });
17203        self.selections_did_change(
17204            false,
17205            &old_cursor_position,
17206            SelectionEffects::default(),
17207            window,
17208            cx,
17209        );
17210    }
17211
17212    pub fn transact(
17213        &mut self,
17214        window: &mut Window,
17215        cx: &mut Context<Self>,
17216        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17217    ) -> Option<TransactionId> {
17218        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17219            this.start_transaction_at(Instant::now(), window, cx);
17220            update(this, window, cx);
17221            this.end_transaction_at(Instant::now(), cx)
17222        })
17223    }
17224
17225    pub fn start_transaction_at(
17226        &mut self,
17227        now: Instant,
17228        window: &mut Window,
17229        cx: &mut Context<Self>,
17230    ) -> Option<TransactionId> {
17231        self.end_selection(window, cx);
17232        if let Some(tx_id) = self
17233            .buffer
17234            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17235        {
17236            self.selection_history
17237                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17238            cx.emit(EditorEvent::TransactionBegun {
17239                transaction_id: tx_id,
17240            });
17241            Some(tx_id)
17242        } else {
17243            None
17244        }
17245    }
17246
17247    pub fn end_transaction_at(
17248        &mut self,
17249        now: Instant,
17250        cx: &mut Context<Self>,
17251    ) -> Option<TransactionId> {
17252        if let Some(transaction_id) = self
17253            .buffer
17254            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17255        {
17256            if let Some((_, end_selections)) =
17257                self.selection_history.transaction_mut(transaction_id)
17258            {
17259                *end_selections = Some(self.selections.disjoint_anchors());
17260            } else {
17261                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17262            }
17263
17264            cx.emit(EditorEvent::Edited { transaction_id });
17265            Some(transaction_id)
17266        } else {
17267            None
17268        }
17269    }
17270
17271    pub fn modify_transaction_selection_history(
17272        &mut self,
17273        transaction_id: TransactionId,
17274        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17275    ) -> bool {
17276        self.selection_history
17277            .transaction_mut(transaction_id)
17278            .map(modify)
17279            .is_some()
17280    }
17281
17282    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17283        if self.selection_mark_mode {
17284            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17285                s.move_with(|_, sel| {
17286                    sel.collapse_to(sel.head(), SelectionGoal::None);
17287                });
17288            })
17289        }
17290        self.selection_mark_mode = true;
17291        cx.notify();
17292    }
17293
17294    pub fn swap_selection_ends(
17295        &mut self,
17296        _: &actions::SwapSelectionEnds,
17297        window: &mut Window,
17298        cx: &mut Context<Self>,
17299    ) {
17300        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17301            s.move_with(|_, sel| {
17302                if sel.start != sel.end {
17303                    sel.reversed = !sel.reversed
17304                }
17305            });
17306        });
17307        self.request_autoscroll(Autoscroll::newest(), cx);
17308        cx.notify();
17309    }
17310
17311    pub fn toggle_focus(
17312        workspace: &mut Workspace,
17313        _: &actions::ToggleFocus,
17314        window: &mut Window,
17315        cx: &mut Context<Workspace>,
17316    ) {
17317        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17318            return;
17319        };
17320        workspace.activate_item(&item, true, true, window, cx);
17321    }
17322
17323    pub fn toggle_fold(
17324        &mut self,
17325        _: &actions::ToggleFold,
17326        window: &mut Window,
17327        cx: &mut Context<Self>,
17328    ) {
17329        if self.is_singleton(cx) {
17330            let selection = self.selections.newest::<Point>(cx);
17331
17332            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17333            let range = if selection.is_empty() {
17334                let point = selection.head().to_display_point(&display_map);
17335                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17336                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17337                    .to_point(&display_map);
17338                start..end
17339            } else {
17340                selection.range()
17341            };
17342            if display_map.folds_in_range(range).next().is_some() {
17343                self.unfold_lines(&Default::default(), window, cx)
17344            } else {
17345                self.fold(&Default::default(), window, cx)
17346            }
17347        } else {
17348            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17349            let buffer_ids: HashSet<_> = self
17350                .selections
17351                .disjoint_anchor_ranges()
17352                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17353                .collect();
17354
17355            let should_unfold = buffer_ids
17356                .iter()
17357                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17358
17359            for buffer_id in buffer_ids {
17360                if should_unfold {
17361                    self.unfold_buffer(buffer_id, cx);
17362                } else {
17363                    self.fold_buffer(buffer_id, cx);
17364                }
17365            }
17366        }
17367    }
17368
17369    pub fn toggle_fold_recursive(
17370        &mut self,
17371        _: &actions::ToggleFoldRecursive,
17372        window: &mut Window,
17373        cx: &mut Context<Self>,
17374    ) {
17375        let selection = self.selections.newest::<Point>(cx);
17376
17377        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17378        let range = if selection.is_empty() {
17379            let point = selection.head().to_display_point(&display_map);
17380            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17381            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17382                .to_point(&display_map);
17383            start..end
17384        } else {
17385            selection.range()
17386        };
17387        if display_map.folds_in_range(range).next().is_some() {
17388            self.unfold_recursive(&Default::default(), window, cx)
17389        } else {
17390            self.fold_recursive(&Default::default(), window, cx)
17391        }
17392    }
17393
17394    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17395        if self.is_singleton(cx) {
17396            let mut to_fold = Vec::new();
17397            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17398            let selections = self.selections.all_adjusted(cx);
17399
17400            for selection in selections {
17401                let range = selection.range().sorted();
17402                let buffer_start_row = range.start.row;
17403
17404                if range.start.row != range.end.row {
17405                    let mut found = false;
17406                    let mut row = range.start.row;
17407                    while row <= range.end.row {
17408                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17409                        {
17410                            found = true;
17411                            row = crease.range().end.row + 1;
17412                            to_fold.push(crease);
17413                        } else {
17414                            row += 1
17415                        }
17416                    }
17417                    if found {
17418                        continue;
17419                    }
17420                }
17421
17422                for row in (0..=range.start.row).rev() {
17423                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17424                        && crease.range().end.row >= buffer_start_row
17425                    {
17426                        to_fold.push(crease);
17427                        if row <= range.start.row {
17428                            break;
17429                        }
17430                    }
17431                }
17432            }
17433
17434            self.fold_creases(to_fold, true, window, cx);
17435        } else {
17436            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17437            let buffer_ids = self
17438                .selections
17439                .disjoint_anchor_ranges()
17440                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17441                .collect::<HashSet<_>>();
17442            for buffer_id in buffer_ids {
17443                self.fold_buffer(buffer_id, cx);
17444            }
17445        }
17446    }
17447
17448    pub fn toggle_fold_all(
17449        &mut self,
17450        _: &actions::ToggleFoldAll,
17451        window: &mut Window,
17452        cx: &mut Context<Self>,
17453    ) {
17454        if self.buffer.read(cx).is_singleton() {
17455            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17456            let has_folds = display_map
17457                .folds_in_range(0..display_map.buffer_snapshot.len())
17458                .next()
17459                .is_some();
17460
17461            if has_folds {
17462                self.unfold_all(&actions::UnfoldAll, window, cx);
17463            } else {
17464                self.fold_all(&actions::FoldAll, window, cx);
17465            }
17466        } else {
17467            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17468            let should_unfold = buffer_ids
17469                .iter()
17470                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17471
17472            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17473                editor
17474                    .update_in(cx, |editor, _, cx| {
17475                        for buffer_id in buffer_ids {
17476                            if should_unfold {
17477                                editor.unfold_buffer(buffer_id, cx);
17478                            } else {
17479                                editor.fold_buffer(buffer_id, cx);
17480                            }
17481                        }
17482                    })
17483                    .ok();
17484            });
17485        }
17486    }
17487
17488    fn fold_at_level(
17489        &mut self,
17490        fold_at: &FoldAtLevel,
17491        window: &mut Window,
17492        cx: &mut Context<Self>,
17493    ) {
17494        if !self.buffer.read(cx).is_singleton() {
17495            return;
17496        }
17497
17498        let fold_at_level = fold_at.0;
17499        let snapshot = self.buffer.read(cx).snapshot(cx);
17500        let mut to_fold = Vec::new();
17501        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17502
17503        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17504            while start_row < end_row {
17505                match self
17506                    .snapshot(window, cx)
17507                    .crease_for_buffer_row(MultiBufferRow(start_row))
17508                {
17509                    Some(crease) => {
17510                        let nested_start_row = crease.range().start.row + 1;
17511                        let nested_end_row = crease.range().end.row;
17512
17513                        if current_level < fold_at_level {
17514                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17515                        } else if current_level == fold_at_level {
17516                            to_fold.push(crease);
17517                        }
17518
17519                        start_row = nested_end_row + 1;
17520                    }
17521                    None => start_row += 1,
17522                }
17523            }
17524        }
17525
17526        self.fold_creases(to_fold, true, window, cx);
17527    }
17528
17529    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17530        if self.buffer.read(cx).is_singleton() {
17531            let mut fold_ranges = Vec::new();
17532            let snapshot = self.buffer.read(cx).snapshot(cx);
17533
17534            for row in 0..snapshot.max_row().0 {
17535                if let Some(foldable_range) = self
17536                    .snapshot(window, cx)
17537                    .crease_for_buffer_row(MultiBufferRow(row))
17538                {
17539                    fold_ranges.push(foldable_range);
17540                }
17541            }
17542
17543            self.fold_creases(fold_ranges, true, window, cx);
17544        } else {
17545            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17546                editor
17547                    .update_in(cx, |editor, _, cx| {
17548                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17549                            editor.fold_buffer(buffer_id, cx);
17550                        }
17551                    })
17552                    .ok();
17553            });
17554        }
17555    }
17556
17557    pub fn fold_function_bodies(
17558        &mut self,
17559        _: &actions::FoldFunctionBodies,
17560        window: &mut Window,
17561        cx: &mut Context<Self>,
17562    ) {
17563        let snapshot = self.buffer.read(cx).snapshot(cx);
17564
17565        let ranges = snapshot
17566            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17567            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17568            .collect::<Vec<_>>();
17569
17570        let creases = ranges
17571            .into_iter()
17572            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17573            .collect();
17574
17575        self.fold_creases(creases, true, window, cx);
17576    }
17577
17578    pub fn fold_recursive(
17579        &mut self,
17580        _: &actions::FoldRecursive,
17581        window: &mut Window,
17582        cx: &mut Context<Self>,
17583    ) {
17584        let mut to_fold = Vec::new();
17585        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17586        let selections = self.selections.all_adjusted(cx);
17587
17588        for selection in selections {
17589            let range = selection.range().sorted();
17590            let buffer_start_row = range.start.row;
17591
17592            if range.start.row != range.end.row {
17593                let mut found = false;
17594                for row in range.start.row..=range.end.row {
17595                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17596                        found = true;
17597                        to_fold.push(crease);
17598                    }
17599                }
17600                if found {
17601                    continue;
17602                }
17603            }
17604
17605            for row in (0..=range.start.row).rev() {
17606                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17607                    if crease.range().end.row >= buffer_start_row {
17608                        to_fold.push(crease);
17609                    } else {
17610                        break;
17611                    }
17612                }
17613            }
17614        }
17615
17616        self.fold_creases(to_fold, true, window, cx);
17617    }
17618
17619    pub fn fold_at(
17620        &mut self,
17621        buffer_row: MultiBufferRow,
17622        window: &mut Window,
17623        cx: &mut Context<Self>,
17624    ) {
17625        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17626
17627        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17628            let autoscroll = self
17629                .selections
17630                .all::<Point>(cx)
17631                .iter()
17632                .any(|selection| crease.range().overlaps(&selection.range()));
17633
17634            self.fold_creases(vec![crease], autoscroll, window, cx);
17635        }
17636    }
17637
17638    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17639        if self.is_singleton(cx) {
17640            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17641            let buffer = &display_map.buffer_snapshot;
17642            let selections = self.selections.all::<Point>(cx);
17643            let ranges = selections
17644                .iter()
17645                .map(|s| {
17646                    let range = s.display_range(&display_map).sorted();
17647                    let mut start = range.start.to_point(&display_map);
17648                    let mut end = range.end.to_point(&display_map);
17649                    start.column = 0;
17650                    end.column = buffer.line_len(MultiBufferRow(end.row));
17651                    start..end
17652                })
17653                .collect::<Vec<_>>();
17654
17655            self.unfold_ranges(&ranges, true, true, cx);
17656        } else {
17657            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17658            let buffer_ids = self
17659                .selections
17660                .disjoint_anchor_ranges()
17661                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17662                .collect::<HashSet<_>>();
17663            for buffer_id in buffer_ids {
17664                self.unfold_buffer(buffer_id, cx);
17665            }
17666        }
17667    }
17668
17669    pub fn unfold_recursive(
17670        &mut self,
17671        _: &UnfoldRecursive,
17672        _window: &mut Window,
17673        cx: &mut Context<Self>,
17674    ) {
17675        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17676        let selections = self.selections.all::<Point>(cx);
17677        let ranges = selections
17678            .iter()
17679            .map(|s| {
17680                let mut range = s.display_range(&display_map).sorted();
17681                *range.start.column_mut() = 0;
17682                *range.end.column_mut() = display_map.line_len(range.end.row());
17683                let start = range.start.to_point(&display_map);
17684                let end = range.end.to_point(&display_map);
17685                start..end
17686            })
17687            .collect::<Vec<_>>();
17688
17689        self.unfold_ranges(&ranges, true, true, cx);
17690    }
17691
17692    pub fn unfold_at(
17693        &mut self,
17694        buffer_row: MultiBufferRow,
17695        _window: &mut Window,
17696        cx: &mut Context<Self>,
17697    ) {
17698        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17699
17700        let intersection_range = Point::new(buffer_row.0, 0)
17701            ..Point::new(
17702                buffer_row.0,
17703                display_map.buffer_snapshot.line_len(buffer_row),
17704            );
17705
17706        let autoscroll = self
17707            .selections
17708            .all::<Point>(cx)
17709            .iter()
17710            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17711
17712        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17713    }
17714
17715    pub fn unfold_all(
17716        &mut self,
17717        _: &actions::UnfoldAll,
17718        _window: &mut Window,
17719        cx: &mut Context<Self>,
17720    ) {
17721        if self.buffer.read(cx).is_singleton() {
17722            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17723            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17724        } else {
17725            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17726                editor
17727                    .update(cx, |editor, cx| {
17728                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17729                            editor.unfold_buffer(buffer_id, cx);
17730                        }
17731                    })
17732                    .ok();
17733            });
17734        }
17735    }
17736
17737    pub fn fold_selected_ranges(
17738        &mut self,
17739        _: &FoldSelectedRanges,
17740        window: &mut Window,
17741        cx: &mut Context<Self>,
17742    ) {
17743        let selections = self.selections.all_adjusted(cx);
17744        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17745        let ranges = selections
17746            .into_iter()
17747            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17748            .collect::<Vec<_>>();
17749        self.fold_creases(ranges, true, window, cx);
17750    }
17751
17752    pub fn fold_ranges<T: ToOffset + Clone>(
17753        &mut self,
17754        ranges: Vec<Range<T>>,
17755        auto_scroll: bool,
17756        window: &mut Window,
17757        cx: &mut Context<Self>,
17758    ) {
17759        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17760        let ranges = ranges
17761            .into_iter()
17762            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17763            .collect::<Vec<_>>();
17764        self.fold_creases(ranges, auto_scroll, window, cx);
17765    }
17766
17767    pub fn fold_creases<T: ToOffset + Clone>(
17768        &mut self,
17769        creases: Vec<Crease<T>>,
17770        auto_scroll: bool,
17771        _window: &mut Window,
17772        cx: &mut Context<Self>,
17773    ) {
17774        if creases.is_empty() {
17775            return;
17776        }
17777
17778        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17779
17780        if auto_scroll {
17781            self.request_autoscroll(Autoscroll::fit(), cx);
17782        }
17783
17784        cx.notify();
17785
17786        self.scrollbar_marker_state.dirty = true;
17787        self.folds_did_change(cx);
17788    }
17789
17790    /// Removes any folds whose ranges intersect any of the given ranges.
17791    pub fn unfold_ranges<T: ToOffset + Clone>(
17792        &mut self,
17793        ranges: &[Range<T>],
17794        inclusive: bool,
17795        auto_scroll: bool,
17796        cx: &mut Context<Self>,
17797    ) {
17798        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17799            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17800        });
17801        self.folds_did_change(cx);
17802    }
17803
17804    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17805        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17806            return;
17807        }
17808        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17809        self.display_map.update(cx, |display_map, cx| {
17810            display_map.fold_buffers([buffer_id], cx)
17811        });
17812        cx.emit(EditorEvent::BufferFoldToggled {
17813            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17814            folded: true,
17815        });
17816        cx.notify();
17817    }
17818
17819    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17820        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17821            return;
17822        }
17823        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17824        self.display_map.update(cx, |display_map, cx| {
17825            display_map.unfold_buffers([buffer_id], cx);
17826        });
17827        cx.emit(EditorEvent::BufferFoldToggled {
17828            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17829            folded: false,
17830        });
17831        cx.notify();
17832    }
17833
17834    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17835        self.display_map.read(cx).is_buffer_folded(buffer)
17836    }
17837
17838    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17839        self.display_map.read(cx).folded_buffers()
17840    }
17841
17842    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17843        self.display_map.update(cx, |display_map, cx| {
17844            display_map.disable_header_for_buffer(buffer_id, cx);
17845        });
17846        cx.notify();
17847    }
17848
17849    /// Removes any folds with the given ranges.
17850    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17851        &mut self,
17852        ranges: &[Range<T>],
17853        type_id: TypeId,
17854        auto_scroll: bool,
17855        cx: &mut Context<Self>,
17856    ) {
17857        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17858            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17859        });
17860        self.folds_did_change(cx);
17861    }
17862
17863    fn remove_folds_with<T: ToOffset + Clone>(
17864        &mut self,
17865        ranges: &[Range<T>],
17866        auto_scroll: bool,
17867        cx: &mut Context<Self>,
17868        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17869    ) {
17870        if ranges.is_empty() {
17871            return;
17872        }
17873
17874        let mut buffers_affected = HashSet::default();
17875        let multi_buffer = self.buffer().read(cx);
17876        for range in ranges {
17877            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17878                buffers_affected.insert(buffer.read(cx).remote_id());
17879            };
17880        }
17881
17882        self.display_map.update(cx, update);
17883
17884        if auto_scroll {
17885            self.request_autoscroll(Autoscroll::fit(), cx);
17886        }
17887
17888        cx.notify();
17889        self.scrollbar_marker_state.dirty = true;
17890        self.active_indent_guides_state.dirty = true;
17891    }
17892
17893    pub fn update_renderer_widths(
17894        &mut self,
17895        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17896        cx: &mut Context<Self>,
17897    ) -> bool {
17898        self.display_map
17899            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17900    }
17901
17902    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17903        self.display_map.read(cx).fold_placeholder.clone()
17904    }
17905
17906    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17907        self.buffer.update(cx, |buffer, cx| {
17908            buffer.set_all_diff_hunks_expanded(cx);
17909        });
17910    }
17911
17912    pub fn expand_all_diff_hunks(
17913        &mut self,
17914        _: &ExpandAllDiffHunks,
17915        _window: &mut Window,
17916        cx: &mut Context<Self>,
17917    ) {
17918        self.buffer.update(cx, |buffer, cx| {
17919            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17920        });
17921    }
17922
17923    pub fn toggle_selected_diff_hunks(
17924        &mut self,
17925        _: &ToggleSelectedDiffHunks,
17926        _window: &mut Window,
17927        cx: &mut Context<Self>,
17928    ) {
17929        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17930        self.toggle_diff_hunks_in_ranges(ranges, cx);
17931    }
17932
17933    pub fn diff_hunks_in_ranges<'a>(
17934        &'a self,
17935        ranges: &'a [Range<Anchor>],
17936        buffer: &'a MultiBufferSnapshot,
17937    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17938        ranges.iter().flat_map(move |range| {
17939            let end_excerpt_id = range.end.excerpt_id;
17940            let range = range.to_point(buffer);
17941            let mut peek_end = range.end;
17942            if range.end.row < buffer.max_row().0 {
17943                peek_end = Point::new(range.end.row + 1, 0);
17944            }
17945            buffer
17946                .diff_hunks_in_range(range.start..peek_end)
17947                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17948        })
17949    }
17950
17951    pub fn has_stageable_diff_hunks_in_ranges(
17952        &self,
17953        ranges: &[Range<Anchor>],
17954        snapshot: &MultiBufferSnapshot,
17955    ) -> bool {
17956        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
17957        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17958    }
17959
17960    pub fn toggle_staged_selected_diff_hunks(
17961        &mut self,
17962        _: &::git::ToggleStaged,
17963        _: &mut Window,
17964        cx: &mut Context<Self>,
17965    ) {
17966        let snapshot = self.buffer.read(cx).snapshot(cx);
17967        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17968        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17969        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17970    }
17971
17972    pub fn set_render_diff_hunk_controls(
17973        &mut self,
17974        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17975        cx: &mut Context<Self>,
17976    ) {
17977        self.render_diff_hunk_controls = render_diff_hunk_controls;
17978        cx.notify();
17979    }
17980
17981    pub fn stage_and_next(
17982        &mut self,
17983        _: &::git::StageAndNext,
17984        window: &mut Window,
17985        cx: &mut Context<Self>,
17986    ) {
17987        self.do_stage_or_unstage_and_next(true, window, cx);
17988    }
17989
17990    pub fn unstage_and_next(
17991        &mut self,
17992        _: &::git::UnstageAndNext,
17993        window: &mut Window,
17994        cx: &mut Context<Self>,
17995    ) {
17996        self.do_stage_or_unstage_and_next(false, window, cx);
17997    }
17998
17999    pub fn stage_or_unstage_diff_hunks(
18000        &mut self,
18001        stage: bool,
18002        ranges: Vec<Range<Anchor>>,
18003        cx: &mut Context<Self>,
18004    ) {
18005        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18006        cx.spawn(async move |this, cx| {
18007            task.await?;
18008            this.update(cx, |this, cx| {
18009                let snapshot = this.buffer.read(cx).snapshot(cx);
18010                let chunk_by = this
18011                    .diff_hunks_in_ranges(&ranges, &snapshot)
18012                    .chunk_by(|hunk| hunk.buffer_id);
18013                for (buffer_id, hunks) in &chunk_by {
18014                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18015                }
18016            })
18017        })
18018        .detach_and_log_err(cx);
18019    }
18020
18021    fn save_buffers_for_ranges_if_needed(
18022        &mut self,
18023        ranges: &[Range<Anchor>],
18024        cx: &mut Context<Editor>,
18025    ) -> Task<Result<()>> {
18026        let multibuffer = self.buffer.read(cx);
18027        let snapshot = multibuffer.read(cx);
18028        let buffer_ids: HashSet<_> = ranges
18029            .iter()
18030            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18031            .collect();
18032        drop(snapshot);
18033
18034        let mut buffers = HashSet::default();
18035        for buffer_id in buffer_ids {
18036            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18037                let buffer = buffer_entity.read(cx);
18038                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18039                {
18040                    buffers.insert(buffer_entity);
18041                }
18042            }
18043        }
18044
18045        if let Some(project) = &self.project {
18046            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18047        } else {
18048            Task::ready(Ok(()))
18049        }
18050    }
18051
18052    fn do_stage_or_unstage_and_next(
18053        &mut self,
18054        stage: bool,
18055        window: &mut Window,
18056        cx: &mut Context<Self>,
18057    ) {
18058        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18059
18060        if ranges.iter().any(|range| range.start != range.end) {
18061            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18062            return;
18063        }
18064
18065        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18066        let snapshot = self.snapshot(window, cx);
18067        let position = self.selections.newest::<Point>(cx).head();
18068        let mut row = snapshot
18069            .buffer_snapshot
18070            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18071            .find(|hunk| hunk.row_range.start.0 > position.row)
18072            .map(|hunk| hunk.row_range.start);
18073
18074        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18075        // Outside of the project diff editor, wrap around to the beginning.
18076        if !all_diff_hunks_expanded {
18077            row = row.or_else(|| {
18078                snapshot
18079                    .buffer_snapshot
18080                    .diff_hunks_in_range(Point::zero()..position)
18081                    .find(|hunk| hunk.row_range.end.0 < position.row)
18082                    .map(|hunk| hunk.row_range.start)
18083            });
18084        }
18085
18086        if let Some(row) = row {
18087            let destination = Point::new(row.0, 0);
18088            let autoscroll = Autoscroll::center();
18089
18090            self.unfold_ranges(&[destination..destination], false, false, cx);
18091            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18092                s.select_ranges([destination..destination]);
18093            });
18094        }
18095    }
18096
18097    fn do_stage_or_unstage(
18098        &self,
18099        stage: bool,
18100        buffer_id: BufferId,
18101        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18102        cx: &mut App,
18103    ) -> Option<()> {
18104        let project = self.project()?;
18105        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18106        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18107        let buffer_snapshot = buffer.read(cx).snapshot();
18108        let file_exists = buffer_snapshot
18109            .file()
18110            .is_some_and(|file| file.disk_state().exists());
18111        diff.update(cx, |diff, cx| {
18112            diff.stage_or_unstage_hunks(
18113                stage,
18114                &hunks
18115                    .map(|hunk| buffer_diff::DiffHunk {
18116                        buffer_range: hunk.buffer_range,
18117                        diff_base_byte_range: hunk.diff_base_byte_range,
18118                        secondary_status: hunk.secondary_status,
18119                        range: Point::zero()..Point::zero(), // unused
18120                    })
18121                    .collect::<Vec<_>>(),
18122                &buffer_snapshot,
18123                file_exists,
18124                cx,
18125            )
18126        });
18127        None
18128    }
18129
18130    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18131        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18132        self.buffer
18133            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18134    }
18135
18136    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18137        self.buffer.update(cx, |buffer, cx| {
18138            let ranges = vec![Anchor::min()..Anchor::max()];
18139            if !buffer.all_diff_hunks_expanded()
18140                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18141            {
18142                buffer.collapse_diff_hunks(ranges, cx);
18143                true
18144            } else {
18145                false
18146            }
18147        })
18148    }
18149
18150    fn toggle_diff_hunks_in_ranges(
18151        &mut self,
18152        ranges: Vec<Range<Anchor>>,
18153        cx: &mut Context<Editor>,
18154    ) {
18155        self.buffer.update(cx, |buffer, cx| {
18156            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18157            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18158        })
18159    }
18160
18161    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18162        self.buffer.update(cx, |buffer, cx| {
18163            let snapshot = buffer.snapshot(cx);
18164            let excerpt_id = range.end.excerpt_id;
18165            let point_range = range.to_point(&snapshot);
18166            let expand = !buffer.single_hunk_is_expanded(range, cx);
18167            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18168        })
18169    }
18170
18171    pub(crate) fn apply_all_diff_hunks(
18172        &mut self,
18173        _: &ApplyAllDiffHunks,
18174        window: &mut Window,
18175        cx: &mut Context<Self>,
18176    ) {
18177        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18178
18179        let buffers = self.buffer.read(cx).all_buffers();
18180        for branch_buffer in buffers {
18181            branch_buffer.update(cx, |branch_buffer, cx| {
18182                branch_buffer.merge_into_base(Vec::new(), cx);
18183            });
18184        }
18185
18186        if let Some(project) = self.project.clone() {
18187            self.save(
18188                SaveOptions {
18189                    format: true,
18190                    autosave: false,
18191                },
18192                project,
18193                window,
18194                cx,
18195            )
18196            .detach_and_log_err(cx);
18197        }
18198    }
18199
18200    pub(crate) fn apply_selected_diff_hunks(
18201        &mut self,
18202        _: &ApplyDiffHunk,
18203        window: &mut Window,
18204        cx: &mut Context<Self>,
18205    ) {
18206        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18207        let snapshot = self.snapshot(window, cx);
18208        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18209        let mut ranges_by_buffer = HashMap::default();
18210        self.transact(window, cx, |editor, _window, cx| {
18211            for hunk in hunks {
18212                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18213                    ranges_by_buffer
18214                        .entry(buffer.clone())
18215                        .or_insert_with(Vec::new)
18216                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18217                }
18218            }
18219
18220            for (buffer, ranges) in ranges_by_buffer {
18221                buffer.update(cx, |buffer, cx| {
18222                    buffer.merge_into_base(ranges, cx);
18223                });
18224            }
18225        });
18226
18227        if let Some(project) = self.project.clone() {
18228            self.save(
18229                SaveOptions {
18230                    format: true,
18231                    autosave: false,
18232                },
18233                project,
18234                window,
18235                cx,
18236            )
18237            .detach_and_log_err(cx);
18238        }
18239    }
18240
18241    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18242        if hovered != self.gutter_hovered {
18243            self.gutter_hovered = hovered;
18244            cx.notify();
18245        }
18246    }
18247
18248    pub fn insert_blocks(
18249        &mut self,
18250        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18251        autoscroll: Option<Autoscroll>,
18252        cx: &mut Context<Self>,
18253    ) -> Vec<CustomBlockId> {
18254        let blocks = self
18255            .display_map
18256            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18257        if let Some(autoscroll) = autoscroll {
18258            self.request_autoscroll(autoscroll, cx);
18259        }
18260        cx.notify();
18261        blocks
18262    }
18263
18264    pub fn resize_blocks(
18265        &mut self,
18266        heights: HashMap<CustomBlockId, u32>,
18267        autoscroll: Option<Autoscroll>,
18268        cx: &mut Context<Self>,
18269    ) {
18270        self.display_map
18271            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18272        if let Some(autoscroll) = autoscroll {
18273            self.request_autoscroll(autoscroll, cx);
18274        }
18275        cx.notify();
18276    }
18277
18278    pub fn replace_blocks(
18279        &mut self,
18280        renderers: HashMap<CustomBlockId, RenderBlock>,
18281        autoscroll: Option<Autoscroll>,
18282        cx: &mut Context<Self>,
18283    ) {
18284        self.display_map
18285            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18286        if let Some(autoscroll) = autoscroll {
18287            self.request_autoscroll(autoscroll, cx);
18288        }
18289        cx.notify();
18290    }
18291
18292    pub fn remove_blocks(
18293        &mut self,
18294        block_ids: HashSet<CustomBlockId>,
18295        autoscroll: Option<Autoscroll>,
18296        cx: &mut Context<Self>,
18297    ) {
18298        self.display_map.update(cx, |display_map, cx| {
18299            display_map.remove_blocks(block_ids, cx)
18300        });
18301        if let Some(autoscroll) = autoscroll {
18302            self.request_autoscroll(autoscroll, cx);
18303        }
18304        cx.notify();
18305    }
18306
18307    pub fn row_for_block(
18308        &self,
18309        block_id: CustomBlockId,
18310        cx: &mut Context<Self>,
18311    ) -> Option<DisplayRow> {
18312        self.display_map
18313            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18314    }
18315
18316    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18317        self.focused_block = Some(focused_block);
18318    }
18319
18320    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18321        self.focused_block.take()
18322    }
18323
18324    pub fn insert_creases(
18325        &mut self,
18326        creases: impl IntoIterator<Item = Crease<Anchor>>,
18327        cx: &mut Context<Self>,
18328    ) -> Vec<CreaseId> {
18329        self.display_map
18330            .update(cx, |map, cx| map.insert_creases(creases, cx))
18331    }
18332
18333    pub fn remove_creases(
18334        &mut self,
18335        ids: impl IntoIterator<Item = CreaseId>,
18336        cx: &mut Context<Self>,
18337    ) -> Vec<(CreaseId, Range<Anchor>)> {
18338        self.display_map
18339            .update(cx, |map, cx| map.remove_creases(ids, cx))
18340    }
18341
18342    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18343        self.display_map
18344            .update(cx, |map, cx| map.snapshot(cx))
18345            .longest_row()
18346    }
18347
18348    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18349        self.display_map
18350            .update(cx, |map, cx| map.snapshot(cx))
18351            .max_point()
18352    }
18353
18354    pub fn text(&self, cx: &App) -> String {
18355        self.buffer.read(cx).read(cx).text()
18356    }
18357
18358    pub fn is_empty(&self, cx: &App) -> bool {
18359        self.buffer.read(cx).read(cx).is_empty()
18360    }
18361
18362    pub fn text_option(&self, cx: &App) -> Option<String> {
18363        let text = self.text(cx);
18364        let text = text.trim();
18365
18366        if text.is_empty() {
18367            return None;
18368        }
18369
18370        Some(text.to_string())
18371    }
18372
18373    pub fn set_text(
18374        &mut self,
18375        text: impl Into<Arc<str>>,
18376        window: &mut Window,
18377        cx: &mut Context<Self>,
18378    ) {
18379        self.transact(window, cx, |this, _, cx| {
18380            this.buffer
18381                .read(cx)
18382                .as_singleton()
18383                .expect("you can only call set_text on editors for singleton buffers")
18384                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18385        });
18386    }
18387
18388    pub fn display_text(&self, cx: &mut App) -> String {
18389        self.display_map
18390            .update(cx, |map, cx| map.snapshot(cx))
18391            .text()
18392    }
18393
18394    fn create_minimap(
18395        &self,
18396        minimap_settings: MinimapSettings,
18397        window: &mut Window,
18398        cx: &mut Context<Self>,
18399    ) -> Option<Entity<Self>> {
18400        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18401            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18402    }
18403
18404    fn initialize_new_minimap(
18405        &self,
18406        minimap_settings: MinimapSettings,
18407        window: &mut Window,
18408        cx: &mut Context<Self>,
18409    ) -> Entity<Self> {
18410        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18411
18412        let mut minimap = Editor::new_internal(
18413            EditorMode::Minimap {
18414                parent: cx.weak_entity(),
18415            },
18416            self.buffer.clone(),
18417            None,
18418            Some(self.display_map.clone()),
18419            window,
18420            cx,
18421        );
18422        minimap.scroll_manager.clone_state(&self.scroll_manager);
18423        minimap.set_text_style_refinement(TextStyleRefinement {
18424            font_size: Some(MINIMAP_FONT_SIZE),
18425            font_weight: Some(MINIMAP_FONT_WEIGHT),
18426            ..Default::default()
18427        });
18428        minimap.update_minimap_configuration(minimap_settings, cx);
18429        cx.new(|_| minimap)
18430    }
18431
18432    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18433        let current_line_highlight = minimap_settings
18434            .current_line_highlight
18435            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18436        self.set_current_line_highlight(Some(current_line_highlight));
18437    }
18438
18439    pub fn minimap(&self) -> Option<&Entity<Self>> {
18440        self.minimap
18441            .as_ref()
18442            .filter(|_| self.minimap_visibility.visible())
18443    }
18444
18445    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18446        let mut wrap_guides = smallvec![];
18447
18448        if self.show_wrap_guides == Some(false) {
18449            return wrap_guides;
18450        }
18451
18452        let settings = self.buffer.read(cx).language_settings(cx);
18453        if settings.show_wrap_guides {
18454            match self.soft_wrap_mode(cx) {
18455                SoftWrap::Column(soft_wrap) => {
18456                    wrap_guides.push((soft_wrap as usize, true));
18457                }
18458                SoftWrap::Bounded(soft_wrap) => {
18459                    wrap_guides.push((soft_wrap as usize, true));
18460                }
18461                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18462            }
18463            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18464        }
18465
18466        wrap_guides
18467    }
18468
18469    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18470        let settings = self.buffer.read(cx).language_settings(cx);
18471        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18472        match mode {
18473            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18474                SoftWrap::None
18475            }
18476            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18477            language_settings::SoftWrap::PreferredLineLength => {
18478                SoftWrap::Column(settings.preferred_line_length)
18479            }
18480            language_settings::SoftWrap::Bounded => {
18481                SoftWrap::Bounded(settings.preferred_line_length)
18482            }
18483        }
18484    }
18485
18486    pub fn set_soft_wrap_mode(
18487        &mut self,
18488        mode: language_settings::SoftWrap,
18489
18490        cx: &mut Context<Self>,
18491    ) {
18492        self.soft_wrap_mode_override = Some(mode);
18493        cx.notify();
18494    }
18495
18496    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18497        self.hard_wrap = hard_wrap;
18498        cx.notify();
18499    }
18500
18501    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18502        self.text_style_refinement = Some(style);
18503    }
18504
18505    /// called by the Element so we know what style we were most recently rendered with.
18506    pub(crate) fn set_style(
18507        &mut self,
18508        style: EditorStyle,
18509        window: &mut Window,
18510        cx: &mut Context<Self>,
18511    ) {
18512        // We intentionally do not inform the display map about the minimap style
18513        // so that wrapping is not recalculated and stays consistent for the editor
18514        // and its linked minimap.
18515        if !self.mode.is_minimap() {
18516            let rem_size = window.rem_size();
18517            self.display_map.update(cx, |map, cx| {
18518                map.set_font(
18519                    style.text.font(),
18520                    style.text.font_size.to_pixels(rem_size),
18521                    cx,
18522                )
18523            });
18524        }
18525        self.style = Some(style);
18526    }
18527
18528    pub fn style(&self) -> Option<&EditorStyle> {
18529        self.style.as_ref()
18530    }
18531
18532    // Called by the element. This method is not designed to be called outside of the editor
18533    // element's layout code because it does not notify when rewrapping is computed synchronously.
18534    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18535        self.display_map
18536            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18537    }
18538
18539    pub fn set_soft_wrap(&mut self) {
18540        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18541    }
18542
18543    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18544        if self.soft_wrap_mode_override.is_some() {
18545            self.soft_wrap_mode_override.take();
18546        } else {
18547            let soft_wrap = match self.soft_wrap_mode(cx) {
18548                SoftWrap::GitDiff => return,
18549                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18550                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18551                    language_settings::SoftWrap::None
18552                }
18553            };
18554            self.soft_wrap_mode_override = Some(soft_wrap);
18555        }
18556        cx.notify();
18557    }
18558
18559    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18560        let Some(workspace) = self.workspace() else {
18561            return;
18562        };
18563        let fs = workspace.read(cx).app_state().fs.clone();
18564        let current_show = TabBarSettings::get_global(cx).show;
18565        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18566            setting.show = Some(!current_show);
18567        });
18568    }
18569
18570    pub fn toggle_indent_guides(
18571        &mut self,
18572        _: &ToggleIndentGuides,
18573        _: &mut Window,
18574        cx: &mut Context<Self>,
18575    ) {
18576        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18577            self.buffer
18578                .read(cx)
18579                .language_settings(cx)
18580                .indent_guides
18581                .enabled
18582        });
18583        self.show_indent_guides = Some(!currently_enabled);
18584        cx.notify();
18585    }
18586
18587    fn should_show_indent_guides(&self) -> Option<bool> {
18588        self.show_indent_guides
18589    }
18590
18591    pub fn toggle_line_numbers(
18592        &mut self,
18593        _: &ToggleLineNumbers,
18594        _: &mut Window,
18595        cx: &mut Context<Self>,
18596    ) {
18597        let mut editor_settings = EditorSettings::get_global(cx).clone();
18598        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18599        EditorSettings::override_global(editor_settings, cx);
18600    }
18601
18602    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18603        if let Some(show_line_numbers) = self.show_line_numbers {
18604            return show_line_numbers;
18605        }
18606        EditorSettings::get_global(cx).gutter.line_numbers
18607    }
18608
18609    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18610        self.use_relative_line_numbers
18611            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18612    }
18613
18614    pub fn toggle_relative_line_numbers(
18615        &mut self,
18616        _: &ToggleRelativeLineNumbers,
18617        _: &mut Window,
18618        cx: &mut Context<Self>,
18619    ) {
18620        let is_relative = self.should_use_relative_line_numbers(cx);
18621        self.set_relative_line_number(Some(!is_relative), cx)
18622    }
18623
18624    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18625        self.use_relative_line_numbers = is_relative;
18626        cx.notify();
18627    }
18628
18629    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18630        self.show_gutter = show_gutter;
18631        cx.notify();
18632    }
18633
18634    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18635        self.show_scrollbars = ScrollbarAxes {
18636            horizontal: show,
18637            vertical: show,
18638        };
18639        cx.notify();
18640    }
18641
18642    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18643        self.show_scrollbars.vertical = show;
18644        cx.notify();
18645    }
18646
18647    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18648        self.show_scrollbars.horizontal = show;
18649        cx.notify();
18650    }
18651
18652    pub fn set_minimap_visibility(
18653        &mut self,
18654        minimap_visibility: MinimapVisibility,
18655        window: &mut Window,
18656        cx: &mut Context<Self>,
18657    ) {
18658        if self.minimap_visibility != minimap_visibility {
18659            if minimap_visibility.visible() && self.minimap.is_none() {
18660                let minimap_settings = EditorSettings::get_global(cx).minimap;
18661                self.minimap =
18662                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18663            }
18664            self.minimap_visibility = minimap_visibility;
18665            cx.notify();
18666        }
18667    }
18668
18669    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18670        self.set_show_scrollbars(false, cx);
18671        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18672    }
18673
18674    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18675        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18676    }
18677
18678    /// Normally the text in full mode and auto height editors is padded on the
18679    /// left side by roughly half a character width for improved hit testing.
18680    ///
18681    /// Use this method to disable this for cases where this is not wanted (e.g.
18682    /// if you want to align the editor text with some other text above or below)
18683    /// or if you want to add this padding to single-line editors.
18684    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18685        self.offset_content = offset_content;
18686        cx.notify();
18687    }
18688
18689    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18690        self.show_line_numbers = Some(show_line_numbers);
18691        cx.notify();
18692    }
18693
18694    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18695        self.disable_expand_excerpt_buttons = true;
18696        cx.notify();
18697    }
18698
18699    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18700        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18701        cx.notify();
18702    }
18703
18704    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18705        self.show_code_actions = Some(show_code_actions);
18706        cx.notify();
18707    }
18708
18709    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18710        self.show_runnables = Some(show_runnables);
18711        cx.notify();
18712    }
18713
18714    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18715        self.show_breakpoints = Some(show_breakpoints);
18716        cx.notify();
18717    }
18718
18719    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18720        if self.display_map.read(cx).masked != masked {
18721            self.display_map.update(cx, |map, _| map.masked = masked);
18722        }
18723        cx.notify()
18724    }
18725
18726    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18727        self.show_wrap_guides = Some(show_wrap_guides);
18728        cx.notify();
18729    }
18730
18731    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18732        self.show_indent_guides = Some(show_indent_guides);
18733        cx.notify();
18734    }
18735
18736    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18737        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18738            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18739                && let Some(dir) = file.abs_path(cx).parent()
18740            {
18741                return Some(dir.to_owned());
18742            }
18743
18744            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18745                return Some(project_path.path.to_path_buf());
18746            }
18747        }
18748
18749        None
18750    }
18751
18752    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18753        self.active_excerpt(cx)?
18754            .1
18755            .read(cx)
18756            .file()
18757            .and_then(|f| f.as_local())
18758    }
18759
18760    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18761        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18762            let buffer = buffer.read(cx);
18763            if let Some(project_path) = buffer.project_path(cx) {
18764                let project = self.project()?.read(cx);
18765                project.absolute_path(&project_path, cx)
18766            } else {
18767                buffer
18768                    .file()
18769                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18770            }
18771        })
18772    }
18773
18774    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18775        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18776            let project_path = buffer.read(cx).project_path(cx)?;
18777            let project = self.project()?.read(cx);
18778            let entry = project.entry_for_path(&project_path, cx)?;
18779            let path = entry.path.to_path_buf();
18780            Some(path)
18781        })
18782    }
18783
18784    pub fn reveal_in_finder(
18785        &mut self,
18786        _: &RevealInFileManager,
18787        _window: &mut Window,
18788        cx: &mut Context<Self>,
18789    ) {
18790        if let Some(target) = self.target_file(cx) {
18791            cx.reveal_path(&target.abs_path(cx));
18792        }
18793    }
18794
18795    pub fn copy_path(
18796        &mut self,
18797        _: &zed_actions::workspace::CopyPath,
18798        _window: &mut Window,
18799        cx: &mut Context<Self>,
18800    ) {
18801        if let Some(path) = self.target_file_abs_path(cx)
18802            && let Some(path) = path.to_str()
18803        {
18804            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18805        }
18806    }
18807
18808    pub fn copy_relative_path(
18809        &mut self,
18810        _: &zed_actions::workspace::CopyRelativePath,
18811        _window: &mut Window,
18812        cx: &mut Context<Self>,
18813    ) {
18814        if let Some(path) = self.target_file_path(cx)
18815            && let Some(path) = path.to_str()
18816        {
18817            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18818        }
18819    }
18820
18821    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18822        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18823            buffer.read(cx).project_path(cx)
18824        } else {
18825            None
18826        }
18827    }
18828
18829    // Returns true if the editor handled a go-to-line request
18830    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18831        maybe!({
18832            let breakpoint_store = self.breakpoint_store.as_ref()?;
18833
18834            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18835            else {
18836                self.clear_row_highlights::<ActiveDebugLine>();
18837                return None;
18838            };
18839
18840            let position = active_stack_frame.position;
18841            let buffer_id = position.buffer_id?;
18842            let snapshot = self
18843                .project
18844                .as_ref()?
18845                .read(cx)
18846                .buffer_for_id(buffer_id, cx)?
18847                .read(cx)
18848                .snapshot();
18849
18850            let mut handled = false;
18851            for (id, ExcerptRange { context, .. }) in
18852                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18853            {
18854                if context.start.cmp(&position, &snapshot).is_ge()
18855                    || context.end.cmp(&position, &snapshot).is_lt()
18856                {
18857                    continue;
18858                }
18859                let snapshot = self.buffer.read(cx).snapshot(cx);
18860                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18861
18862                handled = true;
18863                self.clear_row_highlights::<ActiveDebugLine>();
18864
18865                self.go_to_line::<ActiveDebugLine>(
18866                    multibuffer_anchor,
18867                    Some(cx.theme().colors().editor_debugger_active_line_background),
18868                    window,
18869                    cx,
18870                );
18871
18872                cx.notify();
18873            }
18874
18875            handled.then_some(())
18876        })
18877        .is_some()
18878    }
18879
18880    pub fn copy_file_name_without_extension(
18881        &mut self,
18882        _: &CopyFileNameWithoutExtension,
18883        _: &mut Window,
18884        cx: &mut Context<Self>,
18885    ) {
18886        if let Some(file) = self.target_file(cx)
18887            && let Some(file_stem) = file.path().file_stem()
18888            && let Some(name) = file_stem.to_str()
18889        {
18890            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18891        }
18892    }
18893
18894    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18895        if let Some(file) = self.target_file(cx)
18896            && let Some(file_name) = file.path().file_name()
18897            && let Some(name) = file_name.to_str()
18898        {
18899            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18900        }
18901    }
18902
18903    pub fn toggle_git_blame(
18904        &mut self,
18905        _: &::git::Blame,
18906        window: &mut Window,
18907        cx: &mut Context<Self>,
18908    ) {
18909        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18910
18911        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18912            self.start_git_blame(true, window, cx);
18913        }
18914
18915        cx.notify();
18916    }
18917
18918    pub fn toggle_git_blame_inline(
18919        &mut self,
18920        _: &ToggleGitBlameInline,
18921        window: &mut Window,
18922        cx: &mut Context<Self>,
18923    ) {
18924        self.toggle_git_blame_inline_internal(true, window, cx);
18925        cx.notify();
18926    }
18927
18928    pub fn open_git_blame_commit(
18929        &mut self,
18930        _: &OpenGitBlameCommit,
18931        window: &mut Window,
18932        cx: &mut Context<Self>,
18933    ) {
18934        self.open_git_blame_commit_internal(window, cx);
18935    }
18936
18937    fn open_git_blame_commit_internal(
18938        &mut self,
18939        window: &mut Window,
18940        cx: &mut Context<Self>,
18941    ) -> Option<()> {
18942        let blame = self.blame.as_ref()?;
18943        let snapshot = self.snapshot(window, cx);
18944        let cursor = self.selections.newest::<Point>(cx).head();
18945        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18946        let blame_entry = blame
18947            .update(cx, |blame, cx| {
18948                blame
18949                    .blame_for_rows(
18950                        &[RowInfo {
18951                            buffer_id: Some(buffer.remote_id()),
18952                            buffer_row: Some(point.row),
18953                            ..Default::default()
18954                        }],
18955                        cx,
18956                    )
18957                    .next()
18958            })
18959            .flatten()?;
18960        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18961        let repo = blame.read(cx).repository(cx)?;
18962        let workspace = self.workspace()?.downgrade();
18963        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18964        None
18965    }
18966
18967    pub fn git_blame_inline_enabled(&self) -> bool {
18968        self.git_blame_inline_enabled
18969    }
18970
18971    pub fn toggle_selection_menu(
18972        &mut self,
18973        _: &ToggleSelectionMenu,
18974        _: &mut Window,
18975        cx: &mut Context<Self>,
18976    ) {
18977        self.show_selection_menu = self
18978            .show_selection_menu
18979            .map(|show_selections_menu| !show_selections_menu)
18980            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18981
18982        cx.notify();
18983    }
18984
18985    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18986        self.show_selection_menu
18987            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18988    }
18989
18990    fn start_git_blame(
18991        &mut self,
18992        user_triggered: bool,
18993        window: &mut Window,
18994        cx: &mut Context<Self>,
18995    ) {
18996        if let Some(project) = self.project() {
18997            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18998                return;
18999            };
19000
19001            if buffer.read(cx).file().is_none() {
19002                return;
19003            }
19004
19005            let focused = self.focus_handle(cx).contains_focused(window, cx);
19006
19007            let project = project.clone();
19008            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
19009            self.blame_subscription =
19010                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19011            self.blame = Some(blame);
19012        }
19013    }
19014
19015    fn toggle_git_blame_inline_internal(
19016        &mut self,
19017        user_triggered: bool,
19018        window: &mut Window,
19019        cx: &mut Context<Self>,
19020    ) {
19021        if self.git_blame_inline_enabled {
19022            self.git_blame_inline_enabled = false;
19023            self.show_git_blame_inline = false;
19024            self.show_git_blame_inline_delay_task.take();
19025        } else {
19026            self.git_blame_inline_enabled = true;
19027            self.start_git_blame_inline(user_triggered, window, cx);
19028        }
19029
19030        cx.notify();
19031    }
19032
19033    fn start_git_blame_inline(
19034        &mut self,
19035        user_triggered: bool,
19036        window: &mut Window,
19037        cx: &mut Context<Self>,
19038    ) {
19039        self.start_git_blame(user_triggered, window, cx);
19040
19041        if ProjectSettings::get_global(cx)
19042            .git
19043            .inline_blame_delay()
19044            .is_some()
19045        {
19046            self.start_inline_blame_timer(window, cx);
19047        } else {
19048            self.show_git_blame_inline = true
19049        }
19050    }
19051
19052    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19053        self.blame.as_ref()
19054    }
19055
19056    pub fn show_git_blame_gutter(&self) -> bool {
19057        self.show_git_blame_gutter
19058    }
19059
19060    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19061        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19062    }
19063
19064    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19065        self.show_git_blame_inline
19066            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19067            && !self.newest_selection_head_on_empty_line(cx)
19068            && self.has_blame_entries(cx)
19069    }
19070
19071    fn has_blame_entries(&self, cx: &App) -> bool {
19072        self.blame()
19073            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19074    }
19075
19076    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19077        let cursor_anchor = self.selections.newest_anchor().head();
19078
19079        let snapshot = self.buffer.read(cx).snapshot(cx);
19080        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19081
19082        snapshot.line_len(buffer_row) == 0
19083    }
19084
19085    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19086        let buffer_and_selection = maybe!({
19087            let selection = self.selections.newest::<Point>(cx);
19088            let selection_range = selection.range();
19089
19090            let multi_buffer = self.buffer().read(cx);
19091            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19092            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19093
19094            let (buffer, range, _) = if selection.reversed {
19095                buffer_ranges.first()
19096            } else {
19097                buffer_ranges.last()
19098            }?;
19099
19100            let selection = text::ToPoint::to_point(&range.start, buffer).row
19101                ..text::ToPoint::to_point(&range.end, buffer).row;
19102            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19103        });
19104
19105        let Some((buffer, selection)) = buffer_and_selection else {
19106            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19107        };
19108
19109        let Some(project) = self.project() else {
19110            return Task::ready(Err(anyhow!("editor does not have project")));
19111        };
19112
19113        project.update(cx, |project, cx| {
19114            project.get_permalink_to_line(&buffer, selection, cx)
19115        })
19116    }
19117
19118    pub fn copy_permalink_to_line(
19119        &mut self,
19120        _: &CopyPermalinkToLine,
19121        window: &mut Window,
19122        cx: &mut Context<Self>,
19123    ) {
19124        let permalink_task = self.get_permalink_to_line(cx);
19125        let workspace = self.workspace();
19126
19127        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19128            Ok(permalink) => {
19129                cx.update(|_, cx| {
19130                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19131                })
19132                .ok();
19133            }
19134            Err(err) => {
19135                let message = format!("Failed to copy permalink: {err}");
19136
19137                anyhow::Result::<()>::Err(err).log_err();
19138
19139                if let Some(workspace) = workspace {
19140                    workspace
19141                        .update_in(cx, |workspace, _, cx| {
19142                            struct CopyPermalinkToLine;
19143
19144                            workspace.show_toast(
19145                                Toast::new(
19146                                    NotificationId::unique::<CopyPermalinkToLine>(),
19147                                    message,
19148                                ),
19149                                cx,
19150                            )
19151                        })
19152                        .ok();
19153                }
19154            }
19155        })
19156        .detach();
19157    }
19158
19159    pub fn copy_file_location(
19160        &mut self,
19161        _: &CopyFileLocation,
19162        _: &mut Window,
19163        cx: &mut Context<Self>,
19164    ) {
19165        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19166        if let Some(file) = self.target_file(cx)
19167            && let Some(path) = file.path().to_str()
19168        {
19169            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19170        }
19171    }
19172
19173    pub fn open_permalink_to_line(
19174        &mut self,
19175        _: &OpenPermalinkToLine,
19176        window: &mut Window,
19177        cx: &mut Context<Self>,
19178    ) {
19179        let permalink_task = self.get_permalink_to_line(cx);
19180        let workspace = self.workspace();
19181
19182        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19183            Ok(permalink) => {
19184                cx.update(|_, cx| {
19185                    cx.open_url(permalink.as_ref());
19186                })
19187                .ok();
19188            }
19189            Err(err) => {
19190                let message = format!("Failed to open permalink: {err}");
19191
19192                anyhow::Result::<()>::Err(err).log_err();
19193
19194                if let Some(workspace) = workspace {
19195                    workspace
19196                        .update(cx, |workspace, cx| {
19197                            struct OpenPermalinkToLine;
19198
19199                            workspace.show_toast(
19200                                Toast::new(
19201                                    NotificationId::unique::<OpenPermalinkToLine>(),
19202                                    message,
19203                                ),
19204                                cx,
19205                            )
19206                        })
19207                        .ok();
19208                }
19209            }
19210        })
19211        .detach();
19212    }
19213
19214    pub fn insert_uuid_v4(
19215        &mut self,
19216        _: &InsertUuidV4,
19217        window: &mut Window,
19218        cx: &mut Context<Self>,
19219    ) {
19220        self.insert_uuid(UuidVersion::V4, window, cx);
19221    }
19222
19223    pub fn insert_uuid_v7(
19224        &mut self,
19225        _: &InsertUuidV7,
19226        window: &mut Window,
19227        cx: &mut Context<Self>,
19228    ) {
19229        self.insert_uuid(UuidVersion::V7, window, cx);
19230    }
19231
19232    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19233        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19234        self.transact(window, cx, |this, window, cx| {
19235            let edits = this
19236                .selections
19237                .all::<Point>(cx)
19238                .into_iter()
19239                .map(|selection| {
19240                    let uuid = match version {
19241                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19242                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19243                    };
19244
19245                    (selection.range(), uuid.to_string())
19246                });
19247            this.edit(edits, cx);
19248            this.refresh_edit_prediction(true, false, window, cx);
19249        });
19250    }
19251
19252    pub fn open_selections_in_multibuffer(
19253        &mut self,
19254        _: &OpenSelectionsInMultibuffer,
19255        window: &mut Window,
19256        cx: &mut Context<Self>,
19257    ) {
19258        let multibuffer = self.buffer.read(cx);
19259
19260        let Some(buffer) = multibuffer.as_singleton() else {
19261            return;
19262        };
19263
19264        let Some(workspace) = self.workspace() else {
19265            return;
19266        };
19267
19268        let title = multibuffer.title(cx).to_string();
19269
19270        let locations = self
19271            .selections
19272            .all_anchors(cx)
19273            .iter()
19274            .map(|selection| Location {
19275                buffer: buffer.clone(),
19276                range: selection.start.text_anchor..selection.end.text_anchor,
19277            })
19278            .collect::<Vec<_>>();
19279
19280        cx.spawn_in(window, async move |_, cx| {
19281            workspace.update_in(cx, |workspace, window, cx| {
19282                Self::open_locations_in_multibuffer(
19283                    workspace,
19284                    locations,
19285                    format!("Selections for '{title}'"),
19286                    false,
19287                    MultibufferSelectionMode::All,
19288                    window,
19289                    cx,
19290                );
19291            })
19292        })
19293        .detach();
19294    }
19295
19296    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19297    /// last highlight added will be used.
19298    ///
19299    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19300    pub fn highlight_rows<T: 'static>(
19301        &mut self,
19302        range: Range<Anchor>,
19303        color: Hsla,
19304        options: RowHighlightOptions,
19305        cx: &mut Context<Self>,
19306    ) {
19307        let snapshot = self.buffer().read(cx).snapshot(cx);
19308        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19309        let ix = row_highlights.binary_search_by(|highlight| {
19310            Ordering::Equal
19311                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19312                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19313        });
19314
19315        if let Err(mut ix) = ix {
19316            let index = post_inc(&mut self.highlight_order);
19317
19318            // If this range intersects with the preceding highlight, then merge it with
19319            // the preceding highlight. Otherwise insert a new highlight.
19320            let mut merged = false;
19321            if ix > 0 {
19322                let prev_highlight = &mut row_highlights[ix - 1];
19323                if prev_highlight
19324                    .range
19325                    .end
19326                    .cmp(&range.start, &snapshot)
19327                    .is_ge()
19328                {
19329                    ix -= 1;
19330                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19331                        prev_highlight.range.end = range.end;
19332                    }
19333                    merged = true;
19334                    prev_highlight.index = index;
19335                    prev_highlight.color = color;
19336                    prev_highlight.options = options;
19337                }
19338            }
19339
19340            if !merged {
19341                row_highlights.insert(
19342                    ix,
19343                    RowHighlight {
19344                        range,
19345                        index,
19346                        color,
19347                        options,
19348                        type_id: TypeId::of::<T>(),
19349                    },
19350                );
19351            }
19352
19353            // If any of the following highlights intersect with this one, merge them.
19354            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19355                let highlight = &row_highlights[ix];
19356                if next_highlight
19357                    .range
19358                    .start
19359                    .cmp(&highlight.range.end, &snapshot)
19360                    .is_le()
19361                {
19362                    if next_highlight
19363                        .range
19364                        .end
19365                        .cmp(&highlight.range.end, &snapshot)
19366                        .is_gt()
19367                    {
19368                        row_highlights[ix].range.end = next_highlight.range.end;
19369                    }
19370                    row_highlights.remove(ix + 1);
19371                } else {
19372                    break;
19373                }
19374            }
19375        }
19376    }
19377
19378    /// Remove any highlighted row ranges of the given type that intersect the
19379    /// given ranges.
19380    pub fn remove_highlighted_rows<T: 'static>(
19381        &mut self,
19382        ranges_to_remove: Vec<Range<Anchor>>,
19383        cx: &mut Context<Self>,
19384    ) {
19385        let snapshot = self.buffer().read(cx).snapshot(cx);
19386        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19387        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19388        row_highlights.retain(|highlight| {
19389            while let Some(range_to_remove) = ranges_to_remove.peek() {
19390                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19391                    Ordering::Less | Ordering::Equal => {
19392                        ranges_to_remove.next();
19393                    }
19394                    Ordering::Greater => {
19395                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19396                            Ordering::Less | Ordering::Equal => {
19397                                return false;
19398                            }
19399                            Ordering::Greater => break,
19400                        }
19401                    }
19402                }
19403            }
19404
19405            true
19406        })
19407    }
19408
19409    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19410    pub fn clear_row_highlights<T: 'static>(&mut self) {
19411        self.highlighted_rows.remove(&TypeId::of::<T>());
19412    }
19413
19414    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19415    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19416        self.highlighted_rows
19417            .get(&TypeId::of::<T>())
19418            .map_or(&[] as &[_], |vec| vec.as_slice())
19419            .iter()
19420            .map(|highlight| (highlight.range.clone(), highlight.color))
19421    }
19422
19423    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19424    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19425    /// Allows to ignore certain kinds of highlights.
19426    pub fn highlighted_display_rows(
19427        &self,
19428        window: &mut Window,
19429        cx: &mut App,
19430    ) -> BTreeMap<DisplayRow, LineHighlight> {
19431        let snapshot = self.snapshot(window, cx);
19432        let mut used_highlight_orders = HashMap::default();
19433        self.highlighted_rows
19434            .iter()
19435            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19436            .fold(
19437                BTreeMap::<DisplayRow, LineHighlight>::new(),
19438                |mut unique_rows, highlight| {
19439                    let start = highlight.range.start.to_display_point(&snapshot);
19440                    let end = highlight.range.end.to_display_point(&snapshot);
19441                    let start_row = start.row().0;
19442                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19443                        && end.column() == 0
19444                    {
19445                        end.row().0.saturating_sub(1)
19446                    } else {
19447                        end.row().0
19448                    };
19449                    for row in start_row..=end_row {
19450                        let used_index =
19451                            used_highlight_orders.entry(row).or_insert(highlight.index);
19452                        if highlight.index >= *used_index {
19453                            *used_index = highlight.index;
19454                            unique_rows.insert(
19455                                DisplayRow(row),
19456                                LineHighlight {
19457                                    include_gutter: highlight.options.include_gutter,
19458                                    border: None,
19459                                    background: highlight.color.into(),
19460                                    type_id: Some(highlight.type_id),
19461                                },
19462                            );
19463                        }
19464                    }
19465                    unique_rows
19466                },
19467            )
19468    }
19469
19470    pub fn highlighted_display_row_for_autoscroll(
19471        &self,
19472        snapshot: &DisplaySnapshot,
19473    ) -> Option<DisplayRow> {
19474        self.highlighted_rows
19475            .values()
19476            .flat_map(|highlighted_rows| highlighted_rows.iter())
19477            .filter_map(|highlight| {
19478                if highlight.options.autoscroll {
19479                    Some(highlight.range.start.to_display_point(snapshot).row())
19480                } else {
19481                    None
19482                }
19483            })
19484            .min()
19485    }
19486
19487    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19488        self.highlight_background::<SearchWithinRange>(
19489            ranges,
19490            |colors| colors.colors().editor_document_highlight_read_background,
19491            cx,
19492        )
19493    }
19494
19495    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19496        self.breadcrumb_header = Some(new_header);
19497    }
19498
19499    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19500        self.clear_background_highlights::<SearchWithinRange>(cx);
19501    }
19502
19503    pub fn highlight_background<T: 'static>(
19504        &mut self,
19505        ranges: &[Range<Anchor>],
19506        color_fetcher: fn(&Theme) -> Hsla,
19507        cx: &mut Context<Self>,
19508    ) {
19509        self.background_highlights.insert(
19510            HighlightKey::Type(TypeId::of::<T>()),
19511            (color_fetcher, Arc::from(ranges)),
19512        );
19513        self.scrollbar_marker_state.dirty = true;
19514        cx.notify();
19515    }
19516
19517    pub fn highlight_background_key<T: 'static>(
19518        &mut self,
19519        key: usize,
19520        ranges: &[Range<Anchor>],
19521        color_fetcher: fn(&Theme) -> Hsla,
19522        cx: &mut Context<Self>,
19523    ) {
19524        self.background_highlights.insert(
19525            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19526            (color_fetcher, Arc::from(ranges)),
19527        );
19528        self.scrollbar_marker_state.dirty = true;
19529        cx.notify();
19530    }
19531
19532    pub fn clear_background_highlights<T: 'static>(
19533        &mut self,
19534        cx: &mut Context<Self>,
19535    ) -> Option<BackgroundHighlight> {
19536        let text_highlights = self
19537            .background_highlights
19538            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19539        if !text_highlights.1.is_empty() {
19540            self.scrollbar_marker_state.dirty = true;
19541            cx.notify();
19542        }
19543        Some(text_highlights)
19544    }
19545
19546    pub fn highlight_gutter<T: 'static>(
19547        &mut self,
19548        ranges: impl Into<Vec<Range<Anchor>>>,
19549        color_fetcher: fn(&App) -> Hsla,
19550        cx: &mut Context<Self>,
19551    ) {
19552        self.gutter_highlights
19553            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19554        cx.notify();
19555    }
19556
19557    pub fn clear_gutter_highlights<T: 'static>(
19558        &mut self,
19559        cx: &mut Context<Self>,
19560    ) -> Option<GutterHighlight> {
19561        cx.notify();
19562        self.gutter_highlights.remove(&TypeId::of::<T>())
19563    }
19564
19565    pub fn insert_gutter_highlight<T: 'static>(
19566        &mut self,
19567        range: Range<Anchor>,
19568        color_fetcher: fn(&App) -> Hsla,
19569        cx: &mut Context<Self>,
19570    ) {
19571        let snapshot = self.buffer().read(cx).snapshot(cx);
19572        let mut highlights = self
19573            .gutter_highlights
19574            .remove(&TypeId::of::<T>())
19575            .map(|(_, highlights)| highlights)
19576            .unwrap_or_default();
19577        let ix = highlights.binary_search_by(|highlight| {
19578            Ordering::Equal
19579                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19580                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19581        });
19582        if let Err(ix) = ix {
19583            highlights.insert(ix, range);
19584        }
19585        self.gutter_highlights
19586            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19587    }
19588
19589    pub fn remove_gutter_highlights<T: 'static>(
19590        &mut self,
19591        ranges_to_remove: Vec<Range<Anchor>>,
19592        cx: &mut Context<Self>,
19593    ) {
19594        let snapshot = self.buffer().read(cx).snapshot(cx);
19595        let Some((color_fetcher, mut gutter_highlights)) =
19596            self.gutter_highlights.remove(&TypeId::of::<T>())
19597        else {
19598            return;
19599        };
19600        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19601        gutter_highlights.retain(|highlight| {
19602            while let Some(range_to_remove) = ranges_to_remove.peek() {
19603                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19604                    Ordering::Less | Ordering::Equal => {
19605                        ranges_to_remove.next();
19606                    }
19607                    Ordering::Greater => {
19608                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19609                            Ordering::Less | Ordering::Equal => {
19610                                return false;
19611                            }
19612                            Ordering::Greater => break,
19613                        }
19614                    }
19615                }
19616            }
19617
19618            true
19619        });
19620        self.gutter_highlights
19621            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19622    }
19623
19624    #[cfg(feature = "test-support")]
19625    pub fn all_text_highlights(
19626        &self,
19627        window: &mut Window,
19628        cx: &mut Context<Self>,
19629    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19630        let snapshot = self.snapshot(window, cx);
19631        self.display_map.update(cx, |display_map, _| {
19632            display_map
19633                .all_text_highlights()
19634                .map(|highlight| {
19635                    let (style, ranges) = highlight.as_ref();
19636                    (
19637                        *style,
19638                        ranges
19639                            .iter()
19640                            .map(|range| range.clone().to_display_points(&snapshot))
19641                            .collect(),
19642                    )
19643                })
19644                .collect()
19645        })
19646    }
19647
19648    #[cfg(feature = "test-support")]
19649    pub fn all_text_background_highlights(
19650        &self,
19651        window: &mut Window,
19652        cx: &mut Context<Self>,
19653    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19654        let snapshot = self.snapshot(window, cx);
19655        let buffer = &snapshot.buffer_snapshot;
19656        let start = buffer.anchor_before(0);
19657        let end = buffer.anchor_after(buffer.len());
19658        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19659    }
19660
19661    #[cfg(feature = "test-support")]
19662    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19663        let snapshot = self.buffer().read(cx).snapshot(cx);
19664
19665        let highlights = self
19666            .background_highlights
19667            .get(&HighlightKey::Type(TypeId::of::<
19668                items::BufferSearchHighlights,
19669            >()));
19670
19671        if let Some((_color, ranges)) = highlights {
19672            ranges
19673                .iter()
19674                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19675                .collect_vec()
19676        } else {
19677            vec![]
19678        }
19679    }
19680
19681    fn document_highlights_for_position<'a>(
19682        &'a self,
19683        position: Anchor,
19684        buffer: &'a MultiBufferSnapshot,
19685    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19686        let read_highlights = self
19687            .background_highlights
19688            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19689            .map(|h| &h.1);
19690        let write_highlights = self
19691            .background_highlights
19692            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19693            .map(|h| &h.1);
19694        let left_position = position.bias_left(buffer);
19695        let right_position = position.bias_right(buffer);
19696        read_highlights
19697            .into_iter()
19698            .chain(write_highlights)
19699            .flat_map(move |ranges| {
19700                let start_ix = match ranges.binary_search_by(|probe| {
19701                    let cmp = probe.end.cmp(&left_position, buffer);
19702                    if cmp.is_ge() {
19703                        Ordering::Greater
19704                    } else {
19705                        Ordering::Less
19706                    }
19707                }) {
19708                    Ok(i) | Err(i) => i,
19709                };
19710
19711                ranges[start_ix..]
19712                    .iter()
19713                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19714            })
19715    }
19716
19717    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19718        self.background_highlights
19719            .get(&HighlightKey::Type(TypeId::of::<T>()))
19720            .is_some_and(|(_, highlights)| !highlights.is_empty())
19721    }
19722
19723    pub fn background_highlights_in_range(
19724        &self,
19725        search_range: Range<Anchor>,
19726        display_snapshot: &DisplaySnapshot,
19727        theme: &Theme,
19728    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19729        let mut results = Vec::new();
19730        for (color_fetcher, ranges) in self.background_highlights.values() {
19731            let color = color_fetcher(theme);
19732            let start_ix = match ranges.binary_search_by(|probe| {
19733                let cmp = probe
19734                    .end
19735                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19736                if cmp.is_gt() {
19737                    Ordering::Greater
19738                } else {
19739                    Ordering::Less
19740                }
19741            }) {
19742                Ok(i) | Err(i) => i,
19743            };
19744            for range in &ranges[start_ix..] {
19745                if range
19746                    .start
19747                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19748                    .is_ge()
19749                {
19750                    break;
19751                }
19752
19753                let start = range.start.to_display_point(display_snapshot);
19754                let end = range.end.to_display_point(display_snapshot);
19755                results.push((start..end, color))
19756            }
19757        }
19758        results
19759    }
19760
19761    pub fn background_highlight_row_ranges<T: 'static>(
19762        &self,
19763        search_range: Range<Anchor>,
19764        display_snapshot: &DisplaySnapshot,
19765        count: usize,
19766    ) -> Vec<RangeInclusive<DisplayPoint>> {
19767        let mut results = Vec::new();
19768        let Some((_, ranges)) = self
19769            .background_highlights
19770            .get(&HighlightKey::Type(TypeId::of::<T>()))
19771        else {
19772            return vec![];
19773        };
19774
19775        let start_ix = match ranges.binary_search_by(|probe| {
19776            let cmp = probe
19777                .end
19778                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19779            if cmp.is_gt() {
19780                Ordering::Greater
19781            } else {
19782                Ordering::Less
19783            }
19784        }) {
19785            Ok(i) | Err(i) => i,
19786        };
19787        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19788            if let (Some(start_display), Some(end_display)) = (start, end) {
19789                results.push(
19790                    start_display.to_display_point(display_snapshot)
19791                        ..=end_display.to_display_point(display_snapshot),
19792                );
19793            }
19794        };
19795        let mut start_row: Option<Point> = None;
19796        let mut end_row: Option<Point> = None;
19797        if ranges.len() > count {
19798            return Vec::new();
19799        }
19800        for range in &ranges[start_ix..] {
19801            if range
19802                .start
19803                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19804                .is_ge()
19805            {
19806                break;
19807            }
19808            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19809            if let Some(current_row) = &end_row
19810                && end.row == current_row.row
19811            {
19812                continue;
19813            }
19814            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19815            if start_row.is_none() {
19816                assert_eq!(end_row, None);
19817                start_row = Some(start);
19818                end_row = Some(end);
19819                continue;
19820            }
19821            if let Some(current_end) = end_row.as_mut() {
19822                if start.row > current_end.row + 1 {
19823                    push_region(start_row, end_row);
19824                    start_row = Some(start);
19825                    end_row = Some(end);
19826                } else {
19827                    // Merge two hunks.
19828                    *current_end = end;
19829                }
19830            } else {
19831                unreachable!();
19832            }
19833        }
19834        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19835        push_region(start_row, end_row);
19836        results
19837    }
19838
19839    pub fn gutter_highlights_in_range(
19840        &self,
19841        search_range: Range<Anchor>,
19842        display_snapshot: &DisplaySnapshot,
19843        cx: &App,
19844    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19845        let mut results = Vec::new();
19846        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19847            let color = color_fetcher(cx);
19848            let start_ix = match ranges.binary_search_by(|probe| {
19849                let cmp = probe
19850                    .end
19851                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19852                if cmp.is_gt() {
19853                    Ordering::Greater
19854                } else {
19855                    Ordering::Less
19856                }
19857            }) {
19858                Ok(i) | Err(i) => i,
19859            };
19860            for range in &ranges[start_ix..] {
19861                if range
19862                    .start
19863                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19864                    .is_ge()
19865                {
19866                    break;
19867                }
19868
19869                let start = range.start.to_display_point(display_snapshot);
19870                let end = range.end.to_display_point(display_snapshot);
19871                results.push((start..end, color))
19872            }
19873        }
19874        results
19875    }
19876
19877    /// Get the text ranges corresponding to the redaction query
19878    pub fn redacted_ranges(
19879        &self,
19880        search_range: Range<Anchor>,
19881        display_snapshot: &DisplaySnapshot,
19882        cx: &App,
19883    ) -> Vec<Range<DisplayPoint>> {
19884        display_snapshot
19885            .buffer_snapshot
19886            .redacted_ranges(search_range, |file| {
19887                if let Some(file) = file {
19888                    file.is_private()
19889                        && EditorSettings::get(
19890                            Some(SettingsLocation {
19891                                worktree_id: file.worktree_id(cx),
19892                                path: file.path().as_ref(),
19893                            }),
19894                            cx,
19895                        )
19896                        .redact_private_values
19897                } else {
19898                    false
19899                }
19900            })
19901            .map(|range| {
19902                range.start.to_display_point(display_snapshot)
19903                    ..range.end.to_display_point(display_snapshot)
19904            })
19905            .collect()
19906    }
19907
19908    pub fn highlight_text_key<T: 'static>(
19909        &mut self,
19910        key: usize,
19911        ranges: Vec<Range<Anchor>>,
19912        style: HighlightStyle,
19913        cx: &mut Context<Self>,
19914    ) {
19915        self.display_map.update(cx, |map, _| {
19916            map.highlight_text(
19917                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19918                ranges,
19919                style,
19920            );
19921        });
19922        cx.notify();
19923    }
19924
19925    pub fn highlight_text<T: 'static>(
19926        &mut self,
19927        ranges: Vec<Range<Anchor>>,
19928        style: HighlightStyle,
19929        cx: &mut Context<Self>,
19930    ) {
19931        self.display_map.update(cx, |map, _| {
19932            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19933        });
19934        cx.notify();
19935    }
19936
19937    pub(crate) fn highlight_inlays<T: 'static>(
19938        &mut self,
19939        highlights: Vec<InlayHighlight>,
19940        style: HighlightStyle,
19941        cx: &mut Context<Self>,
19942    ) {
19943        self.display_map.update(cx, |map, _| {
19944            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19945        });
19946        cx.notify();
19947    }
19948
19949    pub fn text_highlights<'a, T: 'static>(
19950        &'a self,
19951        cx: &'a App,
19952    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19953        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19954    }
19955
19956    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19957        let cleared = self
19958            .display_map
19959            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19960        if cleared {
19961            cx.notify();
19962        }
19963    }
19964
19965    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19966        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19967            && self.focus_handle.is_focused(window)
19968    }
19969
19970    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19971        self.show_cursor_when_unfocused = is_enabled;
19972        cx.notify();
19973    }
19974
19975    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19976        cx.notify();
19977    }
19978
19979    fn on_debug_session_event(
19980        &mut self,
19981        _session: Entity<Session>,
19982        event: &SessionEvent,
19983        cx: &mut Context<Self>,
19984    ) {
19985        if let SessionEvent::InvalidateInlineValue = event {
19986            self.refresh_inline_values(cx);
19987        }
19988    }
19989
19990    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19991        let Some(project) = self.project.clone() else {
19992            return;
19993        };
19994
19995        if !self.inline_value_cache.enabled {
19996            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19997            self.splice_inlays(&inlays, Vec::new(), cx);
19998            return;
19999        }
20000
20001        let current_execution_position = self
20002            .highlighted_rows
20003            .get(&TypeId::of::<ActiveDebugLine>())
20004            .and_then(|lines| lines.last().map(|line| line.range.end));
20005
20006        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20007            let inline_values = editor
20008                .update(cx, |editor, cx| {
20009                    let Some(current_execution_position) = current_execution_position else {
20010                        return Some(Task::ready(Ok(Vec::new())));
20011                    };
20012
20013                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20014                        let snapshot = buffer.snapshot(cx);
20015
20016                        let excerpt = snapshot.excerpt_containing(
20017                            current_execution_position..current_execution_position,
20018                        )?;
20019
20020                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20021                    })?;
20022
20023                    let range =
20024                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20025
20026                    project.inline_values(buffer, range, cx)
20027                })
20028                .ok()
20029                .flatten()?
20030                .await
20031                .context("refreshing debugger inlays")
20032                .log_err()?;
20033
20034            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20035
20036            for (buffer_id, inline_value) in inline_values
20037                .into_iter()
20038                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20039            {
20040                buffer_inline_values
20041                    .entry(buffer_id)
20042                    .or_default()
20043                    .push(inline_value);
20044            }
20045
20046            editor
20047                .update(cx, |editor, cx| {
20048                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20049                    let mut new_inlays = Vec::default();
20050
20051                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20052                        let buffer_id = buffer_snapshot.remote_id();
20053                        buffer_inline_values
20054                            .get(&buffer_id)
20055                            .into_iter()
20056                            .flatten()
20057                            .for_each(|hint| {
20058                                let inlay = Inlay::debugger(
20059                                    post_inc(&mut editor.next_inlay_id),
20060                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20061                                    hint.text(),
20062                                );
20063                                if !inlay.text.chars().contains(&'\n') {
20064                                    new_inlays.push(inlay);
20065                                }
20066                            });
20067                    }
20068
20069                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20070                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20071
20072                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20073                })
20074                .ok()?;
20075            Some(())
20076        });
20077    }
20078
20079    fn on_buffer_event(
20080        &mut self,
20081        multibuffer: &Entity<MultiBuffer>,
20082        event: &multi_buffer::Event,
20083        window: &mut Window,
20084        cx: &mut Context<Self>,
20085    ) {
20086        match event {
20087            multi_buffer::Event::Edited {
20088                singleton_buffer_edited,
20089                edited_buffer,
20090            } => {
20091                self.scrollbar_marker_state.dirty = true;
20092                self.active_indent_guides_state.dirty = true;
20093                self.refresh_active_diagnostics(cx);
20094                self.refresh_code_actions(window, cx);
20095                self.refresh_selected_text_highlights(true, window, cx);
20096                self.refresh_single_line_folds(window, cx);
20097                refresh_matching_bracket_highlights(self, window, cx);
20098                if self.has_active_edit_prediction() {
20099                    self.update_visible_edit_prediction(window, cx);
20100                }
20101                if let Some(project) = self.project.as_ref()
20102                    && let Some(edited_buffer) = edited_buffer
20103                {
20104                    project.update(cx, |project, cx| {
20105                        self.registered_buffers
20106                            .entry(edited_buffer.read(cx).remote_id())
20107                            .or_insert_with(|| {
20108                                project.register_buffer_with_language_servers(edited_buffer, cx)
20109                            });
20110                    });
20111                }
20112                cx.emit(EditorEvent::BufferEdited);
20113                cx.emit(SearchEvent::MatchesInvalidated);
20114
20115                if let Some(buffer) = edited_buffer {
20116                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20117                }
20118
20119                if *singleton_buffer_edited {
20120                    if let Some(buffer) = edited_buffer
20121                        && buffer.read(cx).file().is_none()
20122                    {
20123                        cx.emit(EditorEvent::TitleChanged);
20124                    }
20125                    if let Some(project) = &self.project {
20126                        #[allow(clippy::mutable_key_type)]
20127                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20128                            multibuffer
20129                                .all_buffers()
20130                                .into_iter()
20131                                .filter_map(|buffer| {
20132                                    buffer.update(cx, |buffer, cx| {
20133                                        let language = buffer.language()?;
20134                                        let should_discard = project.update(cx, |project, cx| {
20135                                            project.is_local()
20136                                                && !project.has_language_servers_for(buffer, cx)
20137                                        });
20138                                        should_discard.not().then_some(language.clone())
20139                                    })
20140                                })
20141                                .collect::<HashSet<_>>()
20142                        });
20143                        if !languages_affected.is_empty() {
20144                            self.refresh_inlay_hints(
20145                                InlayHintRefreshReason::BufferEdited(languages_affected),
20146                                cx,
20147                            );
20148                        }
20149                    }
20150                }
20151
20152                let Some(project) = &self.project else { return };
20153                let (telemetry, is_via_ssh) = {
20154                    let project = project.read(cx);
20155                    let telemetry = project.client().telemetry().clone();
20156                    let is_via_ssh = project.is_via_remote_server();
20157                    (telemetry, is_via_ssh)
20158                };
20159                refresh_linked_ranges(self, window, cx);
20160                telemetry.log_edit_event("editor", is_via_ssh);
20161            }
20162            multi_buffer::Event::ExcerptsAdded {
20163                buffer,
20164                predecessor,
20165                excerpts,
20166            } => {
20167                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20168                let buffer_id = buffer.read(cx).remote_id();
20169                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20170                    && let Some(project) = &self.project
20171                {
20172                    update_uncommitted_diff_for_buffer(
20173                        cx.entity(),
20174                        project,
20175                        [buffer.clone()],
20176                        self.buffer.clone(),
20177                        cx,
20178                    )
20179                    .detach();
20180                }
20181                self.update_lsp_data(false, Some(buffer_id), window, cx);
20182                cx.emit(EditorEvent::ExcerptsAdded {
20183                    buffer: buffer.clone(),
20184                    predecessor: *predecessor,
20185                    excerpts: excerpts.clone(),
20186                });
20187                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20188            }
20189            multi_buffer::Event::ExcerptsRemoved {
20190                ids,
20191                removed_buffer_ids,
20192            } => {
20193                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20194                let buffer = self.buffer.read(cx);
20195                self.registered_buffers
20196                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20197                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20198                cx.emit(EditorEvent::ExcerptsRemoved {
20199                    ids: ids.clone(),
20200                    removed_buffer_ids: removed_buffer_ids.clone(),
20201                });
20202            }
20203            multi_buffer::Event::ExcerptsEdited {
20204                excerpt_ids,
20205                buffer_ids,
20206            } => {
20207                self.display_map.update(cx, |map, cx| {
20208                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20209                });
20210                cx.emit(EditorEvent::ExcerptsEdited {
20211                    ids: excerpt_ids.clone(),
20212                });
20213            }
20214            multi_buffer::Event::ExcerptsExpanded { ids } => {
20215                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20216                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20217            }
20218            multi_buffer::Event::Reparsed(buffer_id) => {
20219                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20220                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20221
20222                cx.emit(EditorEvent::Reparsed(*buffer_id));
20223            }
20224            multi_buffer::Event::DiffHunksToggled => {
20225                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20226            }
20227            multi_buffer::Event::LanguageChanged(buffer_id) => {
20228                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20229                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20230                cx.emit(EditorEvent::Reparsed(*buffer_id));
20231                cx.notify();
20232            }
20233            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20234            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20235            multi_buffer::Event::FileHandleChanged
20236            | multi_buffer::Event::Reloaded
20237            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20238            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20239            multi_buffer::Event::DiagnosticsUpdated => {
20240                self.update_diagnostics_state(window, cx);
20241            }
20242            _ => {}
20243        };
20244    }
20245
20246    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20247        if !self.diagnostics_enabled() {
20248            return;
20249        }
20250        self.refresh_active_diagnostics(cx);
20251        self.refresh_inline_diagnostics(true, window, cx);
20252        self.scrollbar_marker_state.dirty = true;
20253        cx.notify();
20254    }
20255
20256    pub fn start_temporary_diff_override(&mut self) {
20257        self.load_diff_task.take();
20258        self.temporary_diff_override = true;
20259    }
20260
20261    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20262        self.temporary_diff_override = false;
20263        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20264        self.buffer.update(cx, |buffer, cx| {
20265            buffer.set_all_diff_hunks_collapsed(cx);
20266        });
20267
20268        if let Some(project) = self.project.clone() {
20269            self.load_diff_task = Some(
20270                update_uncommitted_diff_for_buffer(
20271                    cx.entity(),
20272                    &project,
20273                    self.buffer.read(cx).all_buffers(),
20274                    self.buffer.clone(),
20275                    cx,
20276                )
20277                .shared(),
20278            );
20279        }
20280    }
20281
20282    fn on_display_map_changed(
20283        &mut self,
20284        _: Entity<DisplayMap>,
20285        _: &mut Window,
20286        cx: &mut Context<Self>,
20287    ) {
20288        cx.notify();
20289    }
20290
20291    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20292        if self.diagnostics_enabled() {
20293            let new_severity = EditorSettings::get_global(cx)
20294                .diagnostics_max_severity
20295                .unwrap_or(DiagnosticSeverity::Hint);
20296            self.set_max_diagnostics_severity(new_severity, cx);
20297        }
20298        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20299        self.update_edit_prediction_settings(cx);
20300        self.refresh_edit_prediction(true, false, window, cx);
20301        self.refresh_inline_values(cx);
20302        self.refresh_inlay_hints(
20303            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20304                self.selections.newest_anchor().head(),
20305                &self.buffer.read(cx).snapshot(cx),
20306                cx,
20307            )),
20308            cx,
20309        );
20310
20311        let old_cursor_shape = self.cursor_shape;
20312        let old_show_breadcrumbs = self.show_breadcrumbs;
20313
20314        {
20315            let editor_settings = EditorSettings::get_global(cx);
20316            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20317            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20318            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20319            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20320        }
20321
20322        if old_cursor_shape != self.cursor_shape {
20323            cx.emit(EditorEvent::CursorShapeChanged);
20324        }
20325
20326        if old_show_breadcrumbs != self.show_breadcrumbs {
20327            cx.emit(EditorEvent::BreadcrumbsChanged);
20328        }
20329
20330        let project_settings = ProjectSettings::get_global(cx);
20331        self.serialize_dirty_buffers =
20332            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20333
20334        if self.mode.is_full() {
20335            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20336            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20337            if self.show_inline_diagnostics != show_inline_diagnostics {
20338                self.show_inline_diagnostics = show_inline_diagnostics;
20339                self.refresh_inline_diagnostics(false, window, cx);
20340            }
20341
20342            if self.git_blame_inline_enabled != inline_blame_enabled {
20343                self.toggle_git_blame_inline_internal(false, window, cx);
20344            }
20345
20346            let minimap_settings = EditorSettings::get_global(cx).minimap;
20347            if self.minimap_visibility != MinimapVisibility::Disabled {
20348                if self.minimap_visibility.settings_visibility()
20349                    != minimap_settings.minimap_enabled()
20350                {
20351                    self.set_minimap_visibility(
20352                        MinimapVisibility::for_mode(self.mode(), cx),
20353                        window,
20354                        cx,
20355                    );
20356                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20357                    minimap_entity.update(cx, |minimap_editor, cx| {
20358                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20359                    })
20360                }
20361            }
20362        }
20363
20364        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20365            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20366        }) {
20367            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20368                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20369            }
20370            self.refresh_colors(false, None, window, cx);
20371        }
20372
20373        cx.notify();
20374    }
20375
20376    pub fn set_searchable(&mut self, searchable: bool) {
20377        self.searchable = searchable;
20378    }
20379
20380    pub fn searchable(&self) -> bool {
20381        self.searchable
20382    }
20383
20384    fn open_proposed_changes_editor(
20385        &mut self,
20386        _: &OpenProposedChangesEditor,
20387        window: &mut Window,
20388        cx: &mut Context<Self>,
20389    ) {
20390        let Some(workspace) = self.workspace() else {
20391            cx.propagate();
20392            return;
20393        };
20394
20395        let selections = self.selections.all::<usize>(cx);
20396        let multi_buffer = self.buffer.read(cx);
20397        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20398        let mut new_selections_by_buffer = HashMap::default();
20399        for selection in selections {
20400            for (buffer, range, _) in
20401                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20402            {
20403                let mut range = range.to_point(buffer);
20404                range.start.column = 0;
20405                range.end.column = buffer.line_len(range.end.row);
20406                new_selections_by_buffer
20407                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20408                    .or_insert(Vec::new())
20409                    .push(range)
20410            }
20411        }
20412
20413        let proposed_changes_buffers = new_selections_by_buffer
20414            .into_iter()
20415            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20416            .collect::<Vec<_>>();
20417        let proposed_changes_editor = cx.new(|cx| {
20418            ProposedChangesEditor::new(
20419                "Proposed changes",
20420                proposed_changes_buffers,
20421                self.project.clone(),
20422                window,
20423                cx,
20424            )
20425        });
20426
20427        window.defer(cx, move |window, cx| {
20428            workspace.update(cx, |workspace, cx| {
20429                workspace.active_pane().update(cx, |pane, cx| {
20430                    pane.add_item(
20431                        Box::new(proposed_changes_editor),
20432                        true,
20433                        true,
20434                        None,
20435                        window,
20436                        cx,
20437                    );
20438                });
20439            });
20440        });
20441    }
20442
20443    pub fn open_excerpts_in_split(
20444        &mut self,
20445        _: &OpenExcerptsSplit,
20446        window: &mut Window,
20447        cx: &mut Context<Self>,
20448    ) {
20449        self.open_excerpts_common(None, true, window, cx)
20450    }
20451
20452    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20453        self.open_excerpts_common(None, false, window, cx)
20454    }
20455
20456    fn open_excerpts_common(
20457        &mut self,
20458        jump_data: Option<JumpData>,
20459        split: bool,
20460        window: &mut Window,
20461        cx: &mut Context<Self>,
20462    ) {
20463        let Some(workspace) = self.workspace() else {
20464            cx.propagate();
20465            return;
20466        };
20467
20468        if self.buffer.read(cx).is_singleton() {
20469            cx.propagate();
20470            return;
20471        }
20472
20473        let mut new_selections_by_buffer = HashMap::default();
20474        match &jump_data {
20475            Some(JumpData::MultiBufferPoint {
20476                excerpt_id,
20477                position,
20478                anchor,
20479                line_offset_from_top,
20480            }) => {
20481                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20482                if let Some(buffer) = multi_buffer_snapshot
20483                    .buffer_id_for_excerpt(*excerpt_id)
20484                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20485                {
20486                    let buffer_snapshot = buffer.read(cx).snapshot();
20487                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20488                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20489                    } else {
20490                        buffer_snapshot.clip_point(*position, Bias::Left)
20491                    };
20492                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20493                    new_selections_by_buffer.insert(
20494                        buffer,
20495                        (
20496                            vec![jump_to_offset..jump_to_offset],
20497                            Some(*line_offset_from_top),
20498                        ),
20499                    );
20500                }
20501            }
20502            Some(JumpData::MultiBufferRow {
20503                row,
20504                line_offset_from_top,
20505            }) => {
20506                let point = MultiBufferPoint::new(row.0, 0);
20507                if let Some((buffer, buffer_point, _)) =
20508                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20509                {
20510                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20511                    new_selections_by_buffer
20512                        .entry(buffer)
20513                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20514                        .0
20515                        .push(buffer_offset..buffer_offset)
20516                }
20517            }
20518            None => {
20519                let selections = self.selections.all::<usize>(cx);
20520                let multi_buffer = self.buffer.read(cx);
20521                for selection in selections {
20522                    for (snapshot, range, _, anchor) in multi_buffer
20523                        .snapshot(cx)
20524                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20525                    {
20526                        if let Some(anchor) = anchor {
20527                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20528                            else {
20529                                continue;
20530                            };
20531                            let offset = text::ToOffset::to_offset(
20532                                &anchor.text_anchor,
20533                                &buffer_handle.read(cx).snapshot(),
20534                            );
20535                            let range = offset..offset;
20536                            new_selections_by_buffer
20537                                .entry(buffer_handle)
20538                                .or_insert((Vec::new(), None))
20539                                .0
20540                                .push(range)
20541                        } else {
20542                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20543                            else {
20544                                continue;
20545                            };
20546                            new_selections_by_buffer
20547                                .entry(buffer_handle)
20548                                .or_insert((Vec::new(), None))
20549                                .0
20550                                .push(range)
20551                        }
20552                    }
20553                }
20554            }
20555        }
20556
20557        new_selections_by_buffer
20558            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20559
20560        if new_selections_by_buffer.is_empty() {
20561            return;
20562        }
20563
20564        // We defer the pane interaction because we ourselves are a workspace item
20565        // and activating a new item causes the pane to call a method on us reentrantly,
20566        // which panics if we're on the stack.
20567        window.defer(cx, move |window, cx| {
20568            workspace.update(cx, |workspace, cx| {
20569                let pane = if split {
20570                    workspace.adjacent_pane(window, cx)
20571                } else {
20572                    workspace.active_pane().clone()
20573                };
20574
20575                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20576                    let editor = buffer
20577                        .read(cx)
20578                        .file()
20579                        .is_none()
20580                        .then(|| {
20581                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20582                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20583                            // Instead, we try to activate the existing editor in the pane first.
20584                            let (editor, pane_item_index) =
20585                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20586                                    let editor = item.downcast::<Editor>()?;
20587                                    let singleton_buffer =
20588                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20589                                    if singleton_buffer == buffer {
20590                                        Some((editor, i))
20591                                    } else {
20592                                        None
20593                                    }
20594                                })?;
20595                            pane.update(cx, |pane, cx| {
20596                                pane.activate_item(pane_item_index, true, true, window, cx)
20597                            });
20598                            Some(editor)
20599                        })
20600                        .flatten()
20601                        .unwrap_or_else(|| {
20602                            workspace.open_project_item::<Self>(
20603                                pane.clone(),
20604                                buffer,
20605                                true,
20606                                true,
20607                                window,
20608                                cx,
20609                            )
20610                        });
20611
20612                    editor.update(cx, |editor, cx| {
20613                        let autoscroll = match scroll_offset {
20614                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20615                            None => Autoscroll::newest(),
20616                        };
20617                        let nav_history = editor.nav_history.take();
20618                        editor.change_selections(
20619                            SelectionEffects::scroll(autoscroll),
20620                            window,
20621                            cx,
20622                            |s| {
20623                                s.select_ranges(ranges);
20624                            },
20625                        );
20626                        editor.nav_history = nav_history;
20627                    });
20628                }
20629            })
20630        });
20631    }
20632
20633    // For now, don't allow opening excerpts in buffers that aren't backed by
20634    // regular project files.
20635    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20636        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20637    }
20638
20639    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20640        let snapshot = self.buffer.read(cx).read(cx);
20641        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20642        Some(
20643            ranges
20644                .iter()
20645                .map(move |range| {
20646                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20647                })
20648                .collect(),
20649        )
20650    }
20651
20652    fn selection_replacement_ranges(
20653        &self,
20654        range: Range<OffsetUtf16>,
20655        cx: &mut App,
20656    ) -> Vec<Range<OffsetUtf16>> {
20657        let selections = self.selections.all::<OffsetUtf16>(cx);
20658        let newest_selection = selections
20659            .iter()
20660            .max_by_key(|selection| selection.id)
20661            .unwrap();
20662        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20663        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20664        let snapshot = self.buffer.read(cx).read(cx);
20665        selections
20666            .into_iter()
20667            .map(|mut selection| {
20668                selection.start.0 =
20669                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20670                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20671                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20672                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20673            })
20674            .collect()
20675    }
20676
20677    fn report_editor_event(
20678        &self,
20679        reported_event: ReportEditorEvent,
20680        file_extension: Option<String>,
20681        cx: &App,
20682    ) {
20683        if cfg!(any(test, feature = "test-support")) {
20684            return;
20685        }
20686
20687        let Some(project) = &self.project else { return };
20688
20689        // If None, we are in a file without an extension
20690        let file = self
20691            .buffer
20692            .read(cx)
20693            .as_singleton()
20694            .and_then(|b| b.read(cx).file());
20695        let file_extension = file_extension.or(file
20696            .as_ref()
20697            .and_then(|file| Path::new(file.file_name(cx)).extension())
20698            .and_then(|e| e.to_str())
20699            .map(|a| a.to_string()));
20700
20701        let vim_mode = vim_enabled(cx);
20702
20703        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20704        let copilot_enabled = edit_predictions_provider
20705            == language::language_settings::EditPredictionProvider::Copilot;
20706        let copilot_enabled_for_language = self
20707            .buffer
20708            .read(cx)
20709            .language_settings(cx)
20710            .show_edit_predictions;
20711
20712        let project = project.read(cx);
20713        let event_type = reported_event.event_type();
20714
20715        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20716            telemetry::event!(
20717                event_type,
20718                type = if auto_saved {"autosave"} else {"manual"},
20719                file_extension,
20720                vim_mode,
20721                copilot_enabled,
20722                copilot_enabled_for_language,
20723                edit_predictions_provider,
20724                is_via_ssh = project.is_via_remote_server(),
20725            );
20726        } else {
20727            telemetry::event!(
20728                event_type,
20729                file_extension,
20730                vim_mode,
20731                copilot_enabled,
20732                copilot_enabled_for_language,
20733                edit_predictions_provider,
20734                is_via_ssh = project.is_via_remote_server(),
20735            );
20736        };
20737    }
20738
20739    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20740    /// with each line being an array of {text, highlight} objects.
20741    fn copy_highlight_json(
20742        &mut self,
20743        _: &CopyHighlightJson,
20744        window: &mut Window,
20745        cx: &mut Context<Self>,
20746    ) {
20747        #[derive(Serialize)]
20748        struct Chunk<'a> {
20749            text: String,
20750            highlight: Option<&'a str>,
20751        }
20752
20753        let snapshot = self.buffer.read(cx).snapshot(cx);
20754        let range = self
20755            .selected_text_range(false, window, cx)
20756            .and_then(|selection| {
20757                if selection.range.is_empty() {
20758                    None
20759                } else {
20760                    Some(selection.range)
20761                }
20762            })
20763            .unwrap_or_else(|| 0..snapshot.len());
20764
20765        let chunks = snapshot.chunks(range, true);
20766        let mut lines = Vec::new();
20767        let mut line: VecDeque<Chunk> = VecDeque::new();
20768
20769        let Some(style) = self.style.as_ref() else {
20770            return;
20771        };
20772
20773        for chunk in chunks {
20774            let highlight = chunk
20775                .syntax_highlight_id
20776                .and_then(|id| id.name(&style.syntax));
20777            let mut chunk_lines = chunk.text.split('\n').peekable();
20778            while let Some(text) = chunk_lines.next() {
20779                let mut merged_with_last_token = false;
20780                if let Some(last_token) = line.back_mut()
20781                    && last_token.highlight == highlight
20782                {
20783                    last_token.text.push_str(text);
20784                    merged_with_last_token = true;
20785                }
20786
20787                if !merged_with_last_token {
20788                    line.push_back(Chunk {
20789                        text: text.into(),
20790                        highlight,
20791                    });
20792                }
20793
20794                if chunk_lines.peek().is_some() {
20795                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20796                        line.pop_front();
20797                    }
20798                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20799                        line.pop_back();
20800                    }
20801
20802                    lines.push(mem::take(&mut line));
20803                }
20804            }
20805        }
20806
20807        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20808            return;
20809        };
20810        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20811    }
20812
20813    pub fn open_context_menu(
20814        &mut self,
20815        _: &OpenContextMenu,
20816        window: &mut Window,
20817        cx: &mut Context<Self>,
20818    ) {
20819        self.request_autoscroll(Autoscroll::newest(), cx);
20820        let position = self.selections.newest_display(cx).start;
20821        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20822    }
20823
20824    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20825        &self.inlay_hint_cache
20826    }
20827
20828    pub fn replay_insert_event(
20829        &mut self,
20830        text: &str,
20831        relative_utf16_range: Option<Range<isize>>,
20832        window: &mut Window,
20833        cx: &mut Context<Self>,
20834    ) {
20835        if !self.input_enabled {
20836            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20837            return;
20838        }
20839        if let Some(relative_utf16_range) = relative_utf16_range {
20840            let selections = self.selections.all::<OffsetUtf16>(cx);
20841            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20842                let new_ranges = selections.into_iter().map(|range| {
20843                    let start = OffsetUtf16(
20844                        range
20845                            .head()
20846                            .0
20847                            .saturating_add_signed(relative_utf16_range.start),
20848                    );
20849                    let end = OffsetUtf16(
20850                        range
20851                            .head()
20852                            .0
20853                            .saturating_add_signed(relative_utf16_range.end),
20854                    );
20855                    start..end
20856                });
20857                s.select_ranges(new_ranges);
20858            });
20859        }
20860
20861        self.handle_input(text, window, cx);
20862    }
20863
20864    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20865        let Some(provider) = self.semantics_provider.as_ref() else {
20866            return false;
20867        };
20868
20869        let mut supports = false;
20870        self.buffer().update(cx, |this, cx| {
20871            this.for_each_buffer(|buffer| {
20872                supports |= provider.supports_inlay_hints(buffer, cx);
20873            });
20874        });
20875
20876        supports
20877    }
20878
20879    pub fn is_focused(&self, window: &Window) -> bool {
20880        self.focus_handle.is_focused(window)
20881    }
20882
20883    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20884        cx.emit(EditorEvent::Focused);
20885
20886        if let Some(descendant) = self
20887            .last_focused_descendant
20888            .take()
20889            .and_then(|descendant| descendant.upgrade())
20890        {
20891            window.focus(&descendant);
20892        } else {
20893            if let Some(blame) = self.blame.as_ref() {
20894                blame.update(cx, GitBlame::focus)
20895            }
20896
20897            self.blink_manager.update(cx, BlinkManager::enable);
20898            self.show_cursor_names(window, cx);
20899            self.buffer.update(cx, |buffer, cx| {
20900                buffer.finalize_last_transaction(cx);
20901                if self.leader_id.is_none() {
20902                    buffer.set_active_selections(
20903                        &self.selections.disjoint_anchors(),
20904                        self.selections.line_mode,
20905                        self.cursor_shape,
20906                        cx,
20907                    );
20908                }
20909            });
20910        }
20911    }
20912
20913    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20914        cx.emit(EditorEvent::FocusedIn)
20915    }
20916
20917    fn handle_focus_out(
20918        &mut self,
20919        event: FocusOutEvent,
20920        _window: &mut Window,
20921        cx: &mut Context<Self>,
20922    ) {
20923        if event.blurred != self.focus_handle {
20924            self.last_focused_descendant = Some(event.blurred);
20925        }
20926        self.selection_drag_state = SelectionDragState::None;
20927        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20928    }
20929
20930    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20931        self.blink_manager.update(cx, BlinkManager::disable);
20932        self.buffer
20933            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20934
20935        if let Some(blame) = self.blame.as_ref() {
20936            blame.update(cx, GitBlame::blur)
20937        }
20938        if !self.hover_state.focused(window, cx) {
20939            hide_hover(self, cx);
20940        }
20941        if !self
20942            .context_menu
20943            .borrow()
20944            .as_ref()
20945            .is_some_and(|context_menu| context_menu.focused(window, cx))
20946        {
20947            self.hide_context_menu(window, cx);
20948        }
20949        self.discard_edit_prediction(false, cx);
20950        cx.emit(EditorEvent::Blurred);
20951        cx.notify();
20952    }
20953
20954    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20955        let mut pending: String = window
20956            .pending_input_keystrokes()
20957            .into_iter()
20958            .flatten()
20959            .filter_map(|keystroke| {
20960                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20961                    keystroke.key_char.clone()
20962                } else {
20963                    None
20964                }
20965            })
20966            .collect();
20967
20968        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20969            pending = "".to_string();
20970        }
20971
20972        let existing_pending = self
20973            .text_highlights::<PendingInput>(cx)
20974            .map(|(_, ranges)| ranges.to_vec());
20975        if existing_pending.is_none() && pending.is_empty() {
20976            return;
20977        }
20978        let transaction =
20979            self.transact(window, cx, |this, window, cx| {
20980                let selections = this.selections.all::<usize>(cx);
20981                let edits = selections
20982                    .iter()
20983                    .map(|selection| (selection.end..selection.end, pending.clone()));
20984                this.edit(edits, cx);
20985                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20986                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20987                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20988                    }));
20989                });
20990                if let Some(existing_ranges) = existing_pending {
20991                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20992                    this.edit(edits, cx);
20993                }
20994            });
20995
20996        let snapshot = self.snapshot(window, cx);
20997        let ranges = self
20998            .selections
20999            .all::<usize>(cx)
21000            .into_iter()
21001            .map(|selection| {
21002                snapshot.buffer_snapshot.anchor_after(selection.end)
21003                    ..snapshot
21004                        .buffer_snapshot
21005                        .anchor_before(selection.end + pending.len())
21006            })
21007            .collect();
21008
21009        if pending.is_empty() {
21010            self.clear_highlights::<PendingInput>(cx);
21011        } else {
21012            self.highlight_text::<PendingInput>(
21013                ranges,
21014                HighlightStyle {
21015                    underline: Some(UnderlineStyle {
21016                        thickness: px(1.),
21017                        color: None,
21018                        wavy: false,
21019                    }),
21020                    ..Default::default()
21021                },
21022                cx,
21023            );
21024        }
21025
21026        self.ime_transaction = self.ime_transaction.or(transaction);
21027        if let Some(transaction) = self.ime_transaction {
21028            self.buffer.update(cx, |buffer, cx| {
21029                buffer.group_until_transaction(transaction, cx);
21030            });
21031        }
21032
21033        if self.text_highlights::<PendingInput>(cx).is_none() {
21034            self.ime_transaction.take();
21035        }
21036    }
21037
21038    pub fn register_action_renderer(
21039        &mut self,
21040        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21041    ) -> Subscription {
21042        let id = self.next_editor_action_id.post_inc();
21043        self.editor_actions
21044            .borrow_mut()
21045            .insert(id, Box::new(listener));
21046
21047        let editor_actions = self.editor_actions.clone();
21048        Subscription::new(move || {
21049            editor_actions.borrow_mut().remove(&id);
21050        })
21051    }
21052
21053    pub fn register_action<A: Action>(
21054        &mut self,
21055        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21056    ) -> Subscription {
21057        let id = self.next_editor_action_id.post_inc();
21058        let listener = Arc::new(listener);
21059        self.editor_actions.borrow_mut().insert(
21060            id,
21061            Box::new(move |_, window, _| {
21062                let listener = listener.clone();
21063                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21064                    let action = action.downcast_ref().unwrap();
21065                    if phase == DispatchPhase::Bubble {
21066                        listener(action, window, cx)
21067                    }
21068                })
21069            }),
21070        );
21071
21072        let editor_actions = self.editor_actions.clone();
21073        Subscription::new(move || {
21074            editor_actions.borrow_mut().remove(&id);
21075        })
21076    }
21077
21078    pub fn file_header_size(&self) -> u32 {
21079        FILE_HEADER_HEIGHT
21080    }
21081
21082    pub fn restore(
21083        &mut self,
21084        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21085        window: &mut Window,
21086        cx: &mut Context<Self>,
21087    ) {
21088        let workspace = self.workspace();
21089        let project = self.project();
21090        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21091            let mut tasks = Vec::new();
21092            for (buffer_id, changes) in revert_changes {
21093                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21094                    buffer.update(cx, |buffer, cx| {
21095                        buffer.edit(
21096                            changes
21097                                .into_iter()
21098                                .map(|(range, text)| (range, text.to_string())),
21099                            None,
21100                            cx,
21101                        );
21102                    });
21103
21104                    if let Some(project) =
21105                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21106                    {
21107                        project.update(cx, |project, cx| {
21108                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21109                        })
21110                    }
21111                }
21112            }
21113            tasks
21114        });
21115        cx.spawn_in(window, async move |_, cx| {
21116            for (buffer, task) in save_tasks {
21117                let result = task.await;
21118                if result.is_err() {
21119                    let Some(path) = buffer
21120                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21121                        .ok()
21122                    else {
21123                        continue;
21124                    };
21125                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21126                        let Some(task) = cx
21127                            .update_window_entity(workspace, |workspace, window, cx| {
21128                                workspace
21129                                    .open_path_preview(path, None, false, false, false, window, cx)
21130                            })
21131                            .ok()
21132                        else {
21133                            continue;
21134                        };
21135                        task.await.log_err();
21136                    }
21137                }
21138            }
21139        })
21140        .detach();
21141        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21142            selections.refresh()
21143        });
21144    }
21145
21146    pub fn to_pixel_point(
21147        &self,
21148        source: multi_buffer::Anchor,
21149        editor_snapshot: &EditorSnapshot,
21150        window: &mut Window,
21151    ) -> Option<gpui::Point<Pixels>> {
21152        let source_point = source.to_display_point(editor_snapshot);
21153        self.display_to_pixel_point(source_point, editor_snapshot, window)
21154    }
21155
21156    pub fn display_to_pixel_point(
21157        &self,
21158        source: DisplayPoint,
21159        editor_snapshot: &EditorSnapshot,
21160        window: &mut Window,
21161    ) -> Option<gpui::Point<Pixels>> {
21162        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21163        let text_layout_details = self.text_layout_details(window);
21164        let scroll_top = text_layout_details
21165            .scroll_anchor
21166            .scroll_position(editor_snapshot)
21167            .y;
21168
21169        if source.row().as_f32() < scroll_top.floor() {
21170            return None;
21171        }
21172        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21173        let source_y = line_height * (source.row().as_f32() - scroll_top);
21174        Some(gpui::Point::new(source_x, source_y))
21175    }
21176
21177    pub fn has_visible_completions_menu(&self) -> bool {
21178        !self.edit_prediction_preview_is_active()
21179            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21180                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21181            })
21182    }
21183
21184    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21185        if self.mode.is_minimap() {
21186            return;
21187        }
21188        self.addons
21189            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21190    }
21191
21192    pub fn unregister_addon<T: Addon>(&mut self) {
21193        self.addons.remove(&std::any::TypeId::of::<T>());
21194    }
21195
21196    pub fn addon<T: Addon>(&self) -> Option<&T> {
21197        let type_id = std::any::TypeId::of::<T>();
21198        self.addons
21199            .get(&type_id)
21200            .and_then(|item| item.to_any().downcast_ref::<T>())
21201    }
21202
21203    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21204        let type_id = std::any::TypeId::of::<T>();
21205        self.addons
21206            .get_mut(&type_id)
21207            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21208    }
21209
21210    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21211        let text_layout_details = self.text_layout_details(window);
21212        let style = &text_layout_details.editor_style;
21213        let font_id = window.text_system().resolve_font(&style.text.font());
21214        let font_size = style.text.font_size.to_pixels(window.rem_size());
21215        let line_height = style.text.line_height_in_pixels(window.rem_size());
21216        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21217        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21218
21219        CharacterDimensions {
21220            em_width,
21221            em_advance,
21222            line_height,
21223        }
21224    }
21225
21226    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21227        self.load_diff_task.clone()
21228    }
21229
21230    fn read_metadata_from_db(
21231        &mut self,
21232        item_id: u64,
21233        workspace_id: WorkspaceId,
21234        window: &mut Window,
21235        cx: &mut Context<Editor>,
21236    ) {
21237        if self.is_singleton(cx)
21238            && !self.mode.is_minimap()
21239            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21240        {
21241            let buffer_snapshot = OnceCell::new();
21242
21243            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21244                && !folds.is_empty()
21245            {
21246                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21247                self.fold_ranges(
21248                    folds
21249                        .into_iter()
21250                        .map(|(start, end)| {
21251                            snapshot.clip_offset(start, Bias::Left)
21252                                ..snapshot.clip_offset(end, Bias::Right)
21253                        })
21254                        .collect(),
21255                    false,
21256                    window,
21257                    cx,
21258                );
21259            }
21260
21261            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21262                && !selections.is_empty()
21263            {
21264                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21265                // skip adding the initial selection to selection history
21266                self.selection_history.mode = SelectionHistoryMode::Skipping;
21267                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21268                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21269                        snapshot.clip_offset(start, Bias::Left)
21270                            ..snapshot.clip_offset(end, Bias::Right)
21271                    }));
21272                });
21273                self.selection_history.mode = SelectionHistoryMode::Normal;
21274            };
21275        }
21276
21277        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21278    }
21279
21280    fn update_lsp_data(
21281        &mut self,
21282        ignore_cache: bool,
21283        for_buffer: Option<BufferId>,
21284        window: &mut Window,
21285        cx: &mut Context<'_, Self>,
21286    ) {
21287        self.pull_diagnostics(for_buffer, window, cx);
21288        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21289    }
21290}
21291
21292fn vim_enabled(cx: &App) -> bool {
21293    cx.global::<SettingsStore>()
21294        .raw_user_settings()
21295        .get("vim_mode")
21296        == Some(&serde_json::Value::Bool(true))
21297}
21298
21299fn process_completion_for_edit(
21300    completion: &Completion,
21301    intent: CompletionIntent,
21302    buffer: &Entity<Buffer>,
21303    cursor_position: &text::Anchor,
21304    cx: &mut Context<Editor>,
21305) -> CompletionEdit {
21306    let buffer = buffer.read(cx);
21307    let buffer_snapshot = buffer.snapshot();
21308    let (snippet, new_text) = if completion.is_snippet() {
21309        // Workaround for typescript language server issues so that methods don't expand within
21310        // strings and functions with type expressions. The previous point is used because the query
21311        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21312        let mut snippet_source = completion.new_text.clone();
21313        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21314        previous_point.column = previous_point.column.saturating_sub(1);
21315        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21316            && scope.prefers_label_for_snippet_in_completion()
21317            && let Some(label) = completion.label()
21318            && matches!(
21319                completion.kind(),
21320                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21321            )
21322        {
21323            snippet_source = label;
21324        }
21325        match Snippet::parse(&snippet_source).log_err() {
21326            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21327            None => (None, completion.new_text.clone()),
21328        }
21329    } else {
21330        (None, completion.new_text.clone())
21331    };
21332
21333    let mut range_to_replace = {
21334        let replace_range = &completion.replace_range;
21335        if let CompletionSource::Lsp {
21336            insert_range: Some(insert_range),
21337            ..
21338        } = &completion.source
21339        {
21340            debug_assert_eq!(
21341                insert_range.start, replace_range.start,
21342                "insert_range and replace_range should start at the same position"
21343            );
21344            debug_assert!(
21345                insert_range
21346                    .start
21347                    .cmp(cursor_position, &buffer_snapshot)
21348                    .is_le(),
21349                "insert_range should start before or at cursor position"
21350            );
21351            debug_assert!(
21352                replace_range
21353                    .start
21354                    .cmp(cursor_position, &buffer_snapshot)
21355                    .is_le(),
21356                "replace_range should start before or at cursor position"
21357            );
21358
21359            let should_replace = match intent {
21360                CompletionIntent::CompleteWithInsert => false,
21361                CompletionIntent::CompleteWithReplace => true,
21362                CompletionIntent::Complete | CompletionIntent::Compose => {
21363                    let insert_mode =
21364                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21365                            .completions
21366                            .lsp_insert_mode;
21367                    match insert_mode {
21368                        LspInsertMode::Insert => false,
21369                        LspInsertMode::Replace => true,
21370                        LspInsertMode::ReplaceSubsequence => {
21371                            let mut text_to_replace = buffer.chars_for_range(
21372                                buffer.anchor_before(replace_range.start)
21373                                    ..buffer.anchor_after(replace_range.end),
21374                            );
21375                            let mut current_needle = text_to_replace.next();
21376                            for haystack_ch in completion.label.text.chars() {
21377                                if let Some(needle_ch) = current_needle
21378                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21379                                {
21380                                    current_needle = text_to_replace.next();
21381                                }
21382                            }
21383                            current_needle.is_none()
21384                        }
21385                        LspInsertMode::ReplaceSuffix => {
21386                            if replace_range
21387                                .end
21388                                .cmp(cursor_position, &buffer_snapshot)
21389                                .is_gt()
21390                            {
21391                                let range_after_cursor = *cursor_position..replace_range.end;
21392                                let text_after_cursor = buffer
21393                                    .text_for_range(
21394                                        buffer.anchor_before(range_after_cursor.start)
21395                                            ..buffer.anchor_after(range_after_cursor.end),
21396                                    )
21397                                    .collect::<String>()
21398                                    .to_ascii_lowercase();
21399                                completion
21400                                    .label
21401                                    .text
21402                                    .to_ascii_lowercase()
21403                                    .ends_with(&text_after_cursor)
21404                            } else {
21405                                true
21406                            }
21407                        }
21408                    }
21409                }
21410            };
21411
21412            if should_replace {
21413                replace_range.clone()
21414            } else {
21415                insert_range.clone()
21416            }
21417        } else {
21418            replace_range.clone()
21419        }
21420    };
21421
21422    if range_to_replace
21423        .end
21424        .cmp(cursor_position, &buffer_snapshot)
21425        .is_lt()
21426    {
21427        range_to_replace.end = *cursor_position;
21428    }
21429
21430    CompletionEdit {
21431        new_text,
21432        replace_range: range_to_replace.to_offset(buffer),
21433        snippet,
21434    }
21435}
21436
21437struct CompletionEdit {
21438    new_text: String,
21439    replace_range: Range<usize>,
21440    snippet: Option<Snippet>,
21441}
21442
21443fn insert_extra_newline_brackets(
21444    buffer: &MultiBufferSnapshot,
21445    range: Range<usize>,
21446    language: &language::LanguageScope,
21447) -> bool {
21448    let leading_whitespace_len = buffer
21449        .reversed_chars_at(range.start)
21450        .take_while(|c| c.is_whitespace() && *c != '\n')
21451        .map(|c| c.len_utf8())
21452        .sum::<usize>();
21453    let trailing_whitespace_len = buffer
21454        .chars_at(range.end)
21455        .take_while(|c| c.is_whitespace() && *c != '\n')
21456        .map(|c| c.len_utf8())
21457        .sum::<usize>();
21458    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21459
21460    language.brackets().any(|(pair, enabled)| {
21461        let pair_start = pair.start.trim_end();
21462        let pair_end = pair.end.trim_start();
21463
21464        enabled
21465            && pair.newline
21466            && buffer.contains_str_at(range.end, pair_end)
21467            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21468    })
21469}
21470
21471fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21472    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21473        [(buffer, range, _)] => (*buffer, range.clone()),
21474        _ => return false,
21475    };
21476    let pair = {
21477        let mut result: Option<BracketMatch> = None;
21478
21479        for pair in buffer
21480            .all_bracket_ranges(range.clone())
21481            .filter(move |pair| {
21482                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21483            })
21484        {
21485            let len = pair.close_range.end - pair.open_range.start;
21486
21487            if let Some(existing) = &result {
21488                let existing_len = existing.close_range.end - existing.open_range.start;
21489                if len > existing_len {
21490                    continue;
21491                }
21492            }
21493
21494            result = Some(pair);
21495        }
21496
21497        result
21498    };
21499    let Some(pair) = pair else {
21500        return false;
21501    };
21502    pair.newline_only
21503        && buffer
21504            .chars_for_range(pair.open_range.end..range.start)
21505            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21506            .all(|c| c.is_whitespace() && c != '\n')
21507}
21508
21509fn update_uncommitted_diff_for_buffer(
21510    editor: Entity<Editor>,
21511    project: &Entity<Project>,
21512    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21513    buffer: Entity<MultiBuffer>,
21514    cx: &mut App,
21515) -> Task<()> {
21516    let mut tasks = Vec::new();
21517    project.update(cx, |project, cx| {
21518        for buffer in buffers {
21519            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21520                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21521            }
21522        }
21523    });
21524    cx.spawn(async move |cx| {
21525        let diffs = future::join_all(tasks).await;
21526        if editor
21527            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21528            .unwrap_or(false)
21529        {
21530            return;
21531        }
21532
21533        buffer
21534            .update(cx, |buffer, cx| {
21535                for diff in diffs.into_iter().flatten() {
21536                    buffer.add_diff(diff, cx);
21537                }
21538            })
21539            .ok();
21540    })
21541}
21542
21543fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21544    let tab_size = tab_size.get() as usize;
21545    let mut width = offset;
21546
21547    for ch in text.chars() {
21548        width += if ch == '\t' {
21549            tab_size - (width % tab_size)
21550        } else {
21551            1
21552        };
21553    }
21554
21555    width - offset
21556}
21557
21558#[cfg(test)]
21559mod tests {
21560    use super::*;
21561
21562    #[test]
21563    fn test_string_size_with_expanded_tabs() {
21564        let nz = |val| NonZeroU32::new(val).unwrap();
21565        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21566        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21567        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21568        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21569        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21570        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21571        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21572        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21573    }
21574}
21575
21576/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21577struct WordBreakingTokenizer<'a> {
21578    input: &'a str,
21579}
21580
21581impl<'a> WordBreakingTokenizer<'a> {
21582    fn new(input: &'a str) -> Self {
21583        Self { input }
21584    }
21585}
21586
21587fn is_char_ideographic(ch: char) -> bool {
21588    use unicode_script::Script::*;
21589    use unicode_script::UnicodeScript;
21590    matches!(ch.script(), Han | Tangut | Yi)
21591}
21592
21593fn is_grapheme_ideographic(text: &str) -> bool {
21594    text.chars().any(is_char_ideographic)
21595}
21596
21597fn is_grapheme_whitespace(text: &str) -> bool {
21598    text.chars().any(|x| x.is_whitespace())
21599}
21600
21601fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21602    text.chars()
21603        .next()
21604        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21605}
21606
21607#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21608enum WordBreakToken<'a> {
21609    Word { token: &'a str, grapheme_len: usize },
21610    InlineWhitespace { token: &'a str, grapheme_len: usize },
21611    Newline,
21612}
21613
21614impl<'a> Iterator for WordBreakingTokenizer<'a> {
21615    /// Yields a span, the count of graphemes in the token, and whether it was
21616    /// whitespace. Note that it also breaks at word boundaries.
21617    type Item = WordBreakToken<'a>;
21618
21619    fn next(&mut self) -> Option<Self::Item> {
21620        use unicode_segmentation::UnicodeSegmentation;
21621        if self.input.is_empty() {
21622            return None;
21623        }
21624
21625        let mut iter = self.input.graphemes(true).peekable();
21626        let mut offset = 0;
21627        let mut grapheme_len = 0;
21628        if let Some(first_grapheme) = iter.next() {
21629            let is_newline = first_grapheme == "\n";
21630            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21631            offset += first_grapheme.len();
21632            grapheme_len += 1;
21633            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21634                if let Some(grapheme) = iter.peek().copied()
21635                    && should_stay_with_preceding_ideograph(grapheme)
21636                {
21637                    offset += grapheme.len();
21638                    grapheme_len += 1;
21639                }
21640            } else {
21641                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21642                let mut next_word_bound = words.peek().copied();
21643                if next_word_bound.is_some_and(|(i, _)| i == 0) {
21644                    next_word_bound = words.next();
21645                }
21646                while let Some(grapheme) = iter.peek().copied() {
21647                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
21648                        break;
21649                    };
21650                    if is_grapheme_whitespace(grapheme) != is_whitespace
21651                        || (grapheme == "\n") != is_newline
21652                    {
21653                        break;
21654                    };
21655                    offset += grapheme.len();
21656                    grapheme_len += 1;
21657                    iter.next();
21658                }
21659            }
21660            let token = &self.input[..offset];
21661            self.input = &self.input[offset..];
21662            if token == "\n" {
21663                Some(WordBreakToken::Newline)
21664            } else if is_whitespace {
21665                Some(WordBreakToken::InlineWhitespace {
21666                    token,
21667                    grapheme_len,
21668                })
21669            } else {
21670                Some(WordBreakToken::Word {
21671                    token,
21672                    grapheme_len,
21673                })
21674            }
21675        } else {
21676            None
21677        }
21678    }
21679}
21680
21681#[test]
21682fn test_word_breaking_tokenizer() {
21683    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21684        ("", &[]),
21685        ("  ", &[whitespace("  ", 2)]),
21686        ("Ʒ", &[word("Ʒ", 1)]),
21687        ("Ǽ", &[word("Ǽ", 1)]),
21688        ("", &[word("", 1)]),
21689        ("⋑⋑", &[word("⋑⋑", 2)]),
21690        (
21691            "原理,进而",
21692            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21693        ),
21694        (
21695            "hello world",
21696            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21697        ),
21698        (
21699            "hello, world",
21700            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21701        ),
21702        (
21703            "  hello world",
21704            &[
21705                whitespace("  ", 2),
21706                word("hello", 5),
21707                whitespace(" ", 1),
21708                word("world", 5),
21709            ],
21710        ),
21711        (
21712            "这是什么 \n 钢笔",
21713            &[
21714                word("", 1),
21715                word("", 1),
21716                word("", 1),
21717                word("", 1),
21718                whitespace(" ", 1),
21719                newline(),
21720                whitespace(" ", 1),
21721                word("", 1),
21722                word("", 1),
21723            ],
21724        ),
21725        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21726    ];
21727
21728    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21729        WordBreakToken::Word {
21730            token,
21731            grapheme_len,
21732        }
21733    }
21734
21735    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21736        WordBreakToken::InlineWhitespace {
21737            token,
21738            grapheme_len,
21739        }
21740    }
21741
21742    fn newline() -> WordBreakToken<'static> {
21743        WordBreakToken::Newline
21744    }
21745
21746    for (input, result) in tests {
21747        assert_eq!(
21748            WordBreakingTokenizer::new(input)
21749                .collect::<Vec<_>>()
21750                .as_slice(),
21751            *result,
21752        );
21753    }
21754}
21755
21756fn wrap_with_prefix(
21757    first_line_prefix: String,
21758    subsequent_lines_prefix: String,
21759    unwrapped_text: String,
21760    wrap_column: usize,
21761    tab_size: NonZeroU32,
21762    preserve_existing_whitespace: bool,
21763) -> String {
21764    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21765    let subsequent_lines_prefix_len =
21766        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21767    let mut wrapped_text = String::new();
21768    let mut current_line = first_line_prefix;
21769    let mut is_first_line = true;
21770
21771    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21772    let mut current_line_len = first_line_prefix_len;
21773    let mut in_whitespace = false;
21774    for token in tokenizer {
21775        let have_preceding_whitespace = in_whitespace;
21776        match token {
21777            WordBreakToken::Word {
21778                token,
21779                grapheme_len,
21780            } => {
21781                in_whitespace = false;
21782                let current_prefix_len = if is_first_line {
21783                    first_line_prefix_len
21784                } else {
21785                    subsequent_lines_prefix_len
21786                };
21787                if current_line_len + grapheme_len > wrap_column
21788                    && current_line_len != current_prefix_len
21789                {
21790                    wrapped_text.push_str(current_line.trim_end());
21791                    wrapped_text.push('\n');
21792                    is_first_line = false;
21793                    current_line = subsequent_lines_prefix.clone();
21794                    current_line_len = subsequent_lines_prefix_len;
21795                }
21796                current_line.push_str(token);
21797                current_line_len += grapheme_len;
21798            }
21799            WordBreakToken::InlineWhitespace {
21800                mut token,
21801                mut grapheme_len,
21802            } => {
21803                in_whitespace = true;
21804                if have_preceding_whitespace && !preserve_existing_whitespace {
21805                    continue;
21806                }
21807                if !preserve_existing_whitespace {
21808                    token = " ";
21809                    grapheme_len = 1;
21810                }
21811                let current_prefix_len = if is_first_line {
21812                    first_line_prefix_len
21813                } else {
21814                    subsequent_lines_prefix_len
21815                };
21816                if current_line_len + grapheme_len > wrap_column {
21817                    wrapped_text.push_str(current_line.trim_end());
21818                    wrapped_text.push('\n');
21819                    is_first_line = false;
21820                    current_line = subsequent_lines_prefix.clone();
21821                    current_line_len = subsequent_lines_prefix_len;
21822                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21823                    current_line.push_str(token);
21824                    current_line_len += grapheme_len;
21825                }
21826            }
21827            WordBreakToken::Newline => {
21828                in_whitespace = true;
21829                let current_prefix_len = if is_first_line {
21830                    first_line_prefix_len
21831                } else {
21832                    subsequent_lines_prefix_len
21833                };
21834                if preserve_existing_whitespace {
21835                    wrapped_text.push_str(current_line.trim_end());
21836                    wrapped_text.push('\n');
21837                    is_first_line = false;
21838                    current_line = subsequent_lines_prefix.clone();
21839                    current_line_len = subsequent_lines_prefix_len;
21840                } else if have_preceding_whitespace {
21841                    continue;
21842                } else if current_line_len + 1 > wrap_column
21843                    && current_line_len != current_prefix_len
21844                {
21845                    wrapped_text.push_str(current_line.trim_end());
21846                    wrapped_text.push('\n');
21847                    is_first_line = false;
21848                    current_line = subsequent_lines_prefix.clone();
21849                    current_line_len = subsequent_lines_prefix_len;
21850                } else if current_line_len != current_prefix_len {
21851                    current_line.push(' ');
21852                    current_line_len += 1;
21853                }
21854            }
21855        }
21856    }
21857
21858    if !current_line.is_empty() {
21859        wrapped_text.push_str(&current_line);
21860    }
21861    wrapped_text
21862}
21863
21864#[test]
21865fn test_wrap_with_prefix() {
21866    assert_eq!(
21867        wrap_with_prefix(
21868            "# ".to_string(),
21869            "# ".to_string(),
21870            "abcdefg".to_string(),
21871            4,
21872            NonZeroU32::new(4).unwrap(),
21873            false,
21874        ),
21875        "# abcdefg"
21876    );
21877    assert_eq!(
21878        wrap_with_prefix(
21879            "".to_string(),
21880            "".to_string(),
21881            "\thello world".to_string(),
21882            8,
21883            NonZeroU32::new(4).unwrap(),
21884            false,
21885        ),
21886        "hello\nworld"
21887    );
21888    assert_eq!(
21889        wrap_with_prefix(
21890            "// ".to_string(),
21891            "// ".to_string(),
21892            "xx \nyy zz aa bb cc".to_string(),
21893            12,
21894            NonZeroU32::new(4).unwrap(),
21895            false,
21896        ),
21897        "// xx yy zz\n// aa bb cc"
21898    );
21899    assert_eq!(
21900        wrap_with_prefix(
21901            String::new(),
21902            String::new(),
21903            "这是什么 \n 钢笔".to_string(),
21904            3,
21905            NonZeroU32::new(4).unwrap(),
21906            false,
21907        ),
21908        "这是什\n么 钢\n"
21909    );
21910}
21911
21912pub trait CollaborationHub {
21913    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21914    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21915    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21916}
21917
21918impl CollaborationHub for Entity<Project> {
21919    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21920        self.read(cx).collaborators()
21921    }
21922
21923    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21924        self.read(cx).user_store().read(cx).participant_indices()
21925    }
21926
21927    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21928        let this = self.read(cx);
21929        let user_ids = this.collaborators().values().map(|c| c.user_id);
21930        this.user_store().read(cx).participant_names(user_ids, cx)
21931    }
21932}
21933
21934pub trait SemanticsProvider {
21935    fn hover(
21936        &self,
21937        buffer: &Entity<Buffer>,
21938        position: text::Anchor,
21939        cx: &mut App,
21940    ) -> Option<Task<Option<Vec<project::Hover>>>>;
21941
21942    fn inline_values(
21943        &self,
21944        buffer_handle: Entity<Buffer>,
21945        range: Range<text::Anchor>,
21946        cx: &mut App,
21947    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21948
21949    fn inlay_hints(
21950        &self,
21951        buffer_handle: Entity<Buffer>,
21952        range: Range<text::Anchor>,
21953        cx: &mut App,
21954    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21955
21956    fn resolve_inlay_hint(
21957        &self,
21958        hint: InlayHint,
21959        buffer_handle: Entity<Buffer>,
21960        server_id: LanguageServerId,
21961        cx: &mut App,
21962    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21963
21964    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21965
21966    fn document_highlights(
21967        &self,
21968        buffer: &Entity<Buffer>,
21969        position: text::Anchor,
21970        cx: &mut App,
21971    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21972
21973    fn definitions(
21974        &self,
21975        buffer: &Entity<Buffer>,
21976        position: text::Anchor,
21977        kind: GotoDefinitionKind,
21978        cx: &mut App,
21979    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
21980
21981    fn range_for_rename(
21982        &self,
21983        buffer: &Entity<Buffer>,
21984        position: text::Anchor,
21985        cx: &mut App,
21986    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21987
21988    fn perform_rename(
21989        &self,
21990        buffer: &Entity<Buffer>,
21991        position: text::Anchor,
21992        new_name: String,
21993        cx: &mut App,
21994    ) -> Option<Task<Result<ProjectTransaction>>>;
21995}
21996
21997pub trait CompletionProvider {
21998    fn completions(
21999        &self,
22000        excerpt_id: ExcerptId,
22001        buffer: &Entity<Buffer>,
22002        buffer_position: text::Anchor,
22003        trigger: CompletionContext,
22004        window: &mut Window,
22005        cx: &mut Context<Editor>,
22006    ) -> Task<Result<Vec<CompletionResponse>>>;
22007
22008    fn resolve_completions(
22009        &self,
22010        _buffer: Entity<Buffer>,
22011        _completion_indices: Vec<usize>,
22012        _completions: Rc<RefCell<Box<[Completion]>>>,
22013        _cx: &mut Context<Editor>,
22014    ) -> Task<Result<bool>> {
22015        Task::ready(Ok(false))
22016    }
22017
22018    fn apply_additional_edits_for_completion(
22019        &self,
22020        _buffer: Entity<Buffer>,
22021        _completions: Rc<RefCell<Box<[Completion]>>>,
22022        _completion_index: usize,
22023        _push_to_history: bool,
22024        _cx: &mut Context<Editor>,
22025    ) -> Task<Result<Option<language::Transaction>>> {
22026        Task::ready(Ok(None))
22027    }
22028
22029    fn is_completion_trigger(
22030        &self,
22031        buffer: &Entity<Buffer>,
22032        position: language::Anchor,
22033        text: &str,
22034        trigger_in_words: bool,
22035        menu_is_open: bool,
22036        cx: &mut Context<Editor>,
22037    ) -> bool;
22038
22039    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22040
22041    fn sort_completions(&self) -> bool {
22042        true
22043    }
22044
22045    fn filter_completions(&self) -> bool {
22046        true
22047    }
22048}
22049
22050pub trait CodeActionProvider {
22051    fn id(&self) -> Arc<str>;
22052
22053    fn code_actions(
22054        &self,
22055        buffer: &Entity<Buffer>,
22056        range: Range<text::Anchor>,
22057        window: &mut Window,
22058        cx: &mut App,
22059    ) -> Task<Result<Vec<CodeAction>>>;
22060
22061    fn apply_code_action(
22062        &self,
22063        buffer_handle: Entity<Buffer>,
22064        action: CodeAction,
22065        excerpt_id: ExcerptId,
22066        push_to_history: bool,
22067        window: &mut Window,
22068        cx: &mut App,
22069    ) -> Task<Result<ProjectTransaction>>;
22070}
22071
22072impl CodeActionProvider for Entity<Project> {
22073    fn id(&self) -> Arc<str> {
22074        "project".into()
22075    }
22076
22077    fn code_actions(
22078        &self,
22079        buffer: &Entity<Buffer>,
22080        range: Range<text::Anchor>,
22081        _window: &mut Window,
22082        cx: &mut App,
22083    ) -> Task<Result<Vec<CodeAction>>> {
22084        self.update(cx, |project, cx| {
22085            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22086            let code_actions = project.code_actions(buffer, range, None, cx);
22087            cx.background_spawn(async move {
22088                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22089                Ok(code_lens_actions
22090                    .context("code lens fetch")?
22091                    .into_iter()
22092                    .flatten()
22093                    .chain(
22094                        code_actions
22095                            .context("code action fetch")?
22096                            .into_iter()
22097                            .flatten(),
22098                    )
22099                    .collect())
22100            })
22101        })
22102    }
22103
22104    fn apply_code_action(
22105        &self,
22106        buffer_handle: Entity<Buffer>,
22107        action: CodeAction,
22108        _excerpt_id: ExcerptId,
22109        push_to_history: bool,
22110        _window: &mut Window,
22111        cx: &mut App,
22112    ) -> Task<Result<ProjectTransaction>> {
22113        self.update(cx, |project, cx| {
22114            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22115        })
22116    }
22117}
22118
22119fn snippet_completions(
22120    project: &Project,
22121    buffer: &Entity<Buffer>,
22122    buffer_position: text::Anchor,
22123    cx: &mut App,
22124) -> Task<Result<CompletionResponse>> {
22125    let languages = buffer.read(cx).languages_at(buffer_position);
22126    let snippet_store = project.snippets().read(cx);
22127
22128    let scopes: Vec<_> = languages
22129        .iter()
22130        .filter_map(|language| {
22131            let language_name = language.lsp_id();
22132            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22133
22134            if snippets.is_empty() {
22135                None
22136            } else {
22137                Some((language.default_scope(), snippets))
22138            }
22139        })
22140        .collect();
22141
22142    if scopes.is_empty() {
22143        return Task::ready(Ok(CompletionResponse {
22144            completions: vec![],
22145            is_incomplete: false,
22146        }));
22147    }
22148
22149    let snapshot = buffer.read(cx).text_snapshot();
22150    let chars: String = snapshot
22151        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22152        .collect();
22153    let executor = cx.background_executor().clone();
22154
22155    cx.background_spawn(async move {
22156        let mut is_incomplete = false;
22157        let mut completions: Vec<Completion> = Vec::new();
22158        for (scope, snippets) in scopes.into_iter() {
22159            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22160            let mut last_word = chars
22161                .chars()
22162                .take_while(|c| classifier.is_word(*c))
22163                .collect::<String>();
22164            last_word = last_word.chars().rev().collect();
22165
22166            if last_word.is_empty() {
22167                return Ok(CompletionResponse {
22168                    completions: vec![],
22169                    is_incomplete: true,
22170                });
22171            }
22172
22173            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22174            let to_lsp = |point: &text::Anchor| {
22175                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22176                point_to_lsp(end)
22177            };
22178            let lsp_end = to_lsp(&buffer_position);
22179
22180            let candidates = snippets
22181                .iter()
22182                .enumerate()
22183                .flat_map(|(ix, snippet)| {
22184                    snippet
22185                        .prefix
22186                        .iter()
22187                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22188                })
22189                .collect::<Vec<StringMatchCandidate>>();
22190
22191            const MAX_RESULTS: usize = 100;
22192            let mut matches = fuzzy::match_strings(
22193                &candidates,
22194                &last_word,
22195                last_word.chars().any(|c| c.is_uppercase()),
22196                true,
22197                MAX_RESULTS,
22198                &Default::default(),
22199                executor.clone(),
22200            )
22201            .await;
22202
22203            if matches.len() >= MAX_RESULTS {
22204                is_incomplete = true;
22205            }
22206
22207            // Remove all candidates where the query's start does not match the start of any word in the candidate
22208            if let Some(query_start) = last_word.chars().next() {
22209                matches.retain(|string_match| {
22210                    split_words(&string_match.string).any(|word| {
22211                        // Check that the first codepoint of the word as lowercase matches the first
22212                        // codepoint of the query as lowercase
22213                        word.chars()
22214                            .flat_map(|codepoint| codepoint.to_lowercase())
22215                            .zip(query_start.to_lowercase())
22216                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22217                    })
22218                });
22219            }
22220
22221            let matched_strings = matches
22222                .into_iter()
22223                .map(|m| m.string)
22224                .collect::<HashSet<_>>();
22225
22226            completions.extend(snippets.iter().filter_map(|snippet| {
22227                let matching_prefix = snippet
22228                    .prefix
22229                    .iter()
22230                    .find(|prefix| matched_strings.contains(*prefix))?;
22231                let start = as_offset - last_word.len();
22232                let start = snapshot.anchor_before(start);
22233                let range = start..buffer_position;
22234                let lsp_start = to_lsp(&start);
22235                let lsp_range = lsp::Range {
22236                    start: lsp_start,
22237                    end: lsp_end,
22238                };
22239                Some(Completion {
22240                    replace_range: range,
22241                    new_text: snippet.body.clone(),
22242                    source: CompletionSource::Lsp {
22243                        insert_range: None,
22244                        server_id: LanguageServerId(usize::MAX),
22245                        resolved: true,
22246                        lsp_completion: Box::new(lsp::CompletionItem {
22247                            label: snippet.prefix.first().unwrap().clone(),
22248                            kind: Some(CompletionItemKind::SNIPPET),
22249                            label_details: snippet.description.as_ref().map(|description| {
22250                                lsp::CompletionItemLabelDetails {
22251                                    detail: Some(description.clone()),
22252                                    description: None,
22253                                }
22254                            }),
22255                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22256                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22257                                lsp::InsertReplaceEdit {
22258                                    new_text: snippet.body.clone(),
22259                                    insert: lsp_range,
22260                                    replace: lsp_range,
22261                                },
22262                            )),
22263                            filter_text: Some(snippet.body.clone()),
22264                            sort_text: Some(char::MAX.to_string()),
22265                            ..lsp::CompletionItem::default()
22266                        }),
22267                        lsp_defaults: None,
22268                    },
22269                    label: CodeLabel {
22270                        text: matching_prefix.clone(),
22271                        runs: Vec::new(),
22272                        filter_range: 0..matching_prefix.len(),
22273                    },
22274                    icon_path: None,
22275                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22276                        single_line: snippet.name.clone().into(),
22277                        plain_text: snippet
22278                            .description
22279                            .clone()
22280                            .map(|description| description.into()),
22281                    }),
22282                    insert_text_mode: None,
22283                    confirm: None,
22284                })
22285            }))
22286        }
22287
22288        Ok(CompletionResponse {
22289            completions,
22290            is_incomplete,
22291        })
22292    })
22293}
22294
22295impl CompletionProvider for Entity<Project> {
22296    fn completions(
22297        &self,
22298        _excerpt_id: ExcerptId,
22299        buffer: &Entity<Buffer>,
22300        buffer_position: text::Anchor,
22301        options: CompletionContext,
22302        _window: &mut Window,
22303        cx: &mut Context<Editor>,
22304    ) -> Task<Result<Vec<CompletionResponse>>> {
22305        self.update(cx, |project, cx| {
22306            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22307            let project_completions = project.completions(buffer, buffer_position, options, cx);
22308            cx.background_spawn(async move {
22309                let mut responses = project_completions.await?;
22310                let snippets = snippets.await?;
22311                if !snippets.completions.is_empty() {
22312                    responses.push(snippets);
22313                }
22314                Ok(responses)
22315            })
22316        })
22317    }
22318
22319    fn resolve_completions(
22320        &self,
22321        buffer: Entity<Buffer>,
22322        completion_indices: Vec<usize>,
22323        completions: Rc<RefCell<Box<[Completion]>>>,
22324        cx: &mut Context<Editor>,
22325    ) -> Task<Result<bool>> {
22326        self.update(cx, |project, cx| {
22327            project.lsp_store().update(cx, |lsp_store, cx| {
22328                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22329            })
22330        })
22331    }
22332
22333    fn apply_additional_edits_for_completion(
22334        &self,
22335        buffer: Entity<Buffer>,
22336        completions: Rc<RefCell<Box<[Completion]>>>,
22337        completion_index: usize,
22338        push_to_history: bool,
22339        cx: &mut Context<Editor>,
22340    ) -> Task<Result<Option<language::Transaction>>> {
22341        self.update(cx, |project, cx| {
22342            project.lsp_store().update(cx, |lsp_store, cx| {
22343                lsp_store.apply_additional_edits_for_completion(
22344                    buffer,
22345                    completions,
22346                    completion_index,
22347                    push_to_history,
22348                    cx,
22349                )
22350            })
22351        })
22352    }
22353
22354    fn is_completion_trigger(
22355        &self,
22356        buffer: &Entity<Buffer>,
22357        position: language::Anchor,
22358        text: &str,
22359        trigger_in_words: bool,
22360        menu_is_open: bool,
22361        cx: &mut Context<Editor>,
22362    ) -> bool {
22363        let mut chars = text.chars();
22364        let char = if let Some(char) = chars.next() {
22365            char
22366        } else {
22367            return false;
22368        };
22369        if chars.next().is_some() {
22370            return false;
22371        }
22372
22373        let buffer = buffer.read(cx);
22374        let snapshot = buffer.snapshot();
22375        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22376            return false;
22377        }
22378        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22379        if trigger_in_words && classifier.is_word(char) {
22380            return true;
22381        }
22382
22383        buffer.completion_triggers().contains(text)
22384    }
22385}
22386
22387impl SemanticsProvider for Entity<Project> {
22388    fn hover(
22389        &self,
22390        buffer: &Entity<Buffer>,
22391        position: text::Anchor,
22392        cx: &mut App,
22393    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22394        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22395    }
22396
22397    fn document_highlights(
22398        &self,
22399        buffer: &Entity<Buffer>,
22400        position: text::Anchor,
22401        cx: &mut App,
22402    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22403        Some(self.update(cx, |project, cx| {
22404            project.document_highlights(buffer, position, cx)
22405        }))
22406    }
22407
22408    fn definitions(
22409        &self,
22410        buffer: &Entity<Buffer>,
22411        position: text::Anchor,
22412        kind: GotoDefinitionKind,
22413        cx: &mut App,
22414    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22415        Some(self.update(cx, |project, cx| match kind {
22416            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22417            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22418            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22419            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22420        }))
22421    }
22422
22423    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22424        self.update(cx, |project, cx| {
22425            if project
22426                .active_debug_session(cx)
22427                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22428            {
22429                return true;
22430            }
22431
22432            buffer.update(cx, |buffer, cx| {
22433                project.any_language_server_supports_inlay_hints(buffer, cx)
22434            })
22435        })
22436    }
22437
22438    fn inline_values(
22439        &self,
22440        buffer_handle: Entity<Buffer>,
22441        range: Range<text::Anchor>,
22442        cx: &mut App,
22443    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22444        self.update(cx, |project, cx| {
22445            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22446
22447            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22448        })
22449    }
22450
22451    fn inlay_hints(
22452        &self,
22453        buffer_handle: Entity<Buffer>,
22454        range: Range<text::Anchor>,
22455        cx: &mut App,
22456    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22457        Some(self.update(cx, |project, cx| {
22458            project.inlay_hints(buffer_handle, range, cx)
22459        }))
22460    }
22461
22462    fn resolve_inlay_hint(
22463        &self,
22464        hint: InlayHint,
22465        buffer_handle: Entity<Buffer>,
22466        server_id: LanguageServerId,
22467        cx: &mut App,
22468    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22469        Some(self.update(cx, |project, cx| {
22470            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22471        }))
22472    }
22473
22474    fn range_for_rename(
22475        &self,
22476        buffer: &Entity<Buffer>,
22477        position: text::Anchor,
22478        cx: &mut App,
22479    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22480        Some(self.update(cx, |project, cx| {
22481            let buffer = buffer.clone();
22482            let task = project.prepare_rename(buffer.clone(), position, cx);
22483            cx.spawn(async move |_, cx| {
22484                Ok(match task.await? {
22485                    PrepareRenameResponse::Success(range) => Some(range),
22486                    PrepareRenameResponse::InvalidPosition => None,
22487                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22488                        // Fallback on using TreeSitter info to determine identifier range
22489                        buffer.read_with(cx, |buffer, _| {
22490                            let snapshot = buffer.snapshot();
22491                            let (range, kind) = snapshot.surrounding_word(position, false);
22492                            if kind != Some(CharKind::Word) {
22493                                return None;
22494                            }
22495                            Some(
22496                                snapshot.anchor_before(range.start)
22497                                    ..snapshot.anchor_after(range.end),
22498                            )
22499                        })?
22500                    }
22501                })
22502            })
22503        }))
22504    }
22505
22506    fn perform_rename(
22507        &self,
22508        buffer: &Entity<Buffer>,
22509        position: text::Anchor,
22510        new_name: String,
22511        cx: &mut App,
22512    ) -> Option<Task<Result<ProjectTransaction>>> {
22513        Some(self.update(cx, |project, cx| {
22514            project.perform_rename(buffer.clone(), position, new_name, cx)
22515        }))
22516    }
22517}
22518
22519fn inlay_hint_settings(
22520    location: Anchor,
22521    snapshot: &MultiBufferSnapshot,
22522    cx: &mut Context<Editor>,
22523) -> InlayHintSettings {
22524    let file = snapshot.file_at(location);
22525    let language = snapshot.language_at(location).map(|l| l.name());
22526    language_settings(language, file, cx).inlay_hints
22527}
22528
22529fn consume_contiguous_rows(
22530    contiguous_row_selections: &mut Vec<Selection<Point>>,
22531    selection: &Selection<Point>,
22532    display_map: &DisplaySnapshot,
22533    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22534) -> (MultiBufferRow, MultiBufferRow) {
22535    contiguous_row_selections.push(selection.clone());
22536    let start_row = starting_row(selection, display_map);
22537    let mut end_row = ending_row(selection, display_map);
22538
22539    while let Some(next_selection) = selections.peek() {
22540        if next_selection.start.row <= end_row.0 {
22541            end_row = ending_row(next_selection, display_map);
22542            contiguous_row_selections.push(selections.next().unwrap().clone());
22543        } else {
22544            break;
22545        }
22546    }
22547    (start_row, end_row)
22548}
22549
22550fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22551    if selection.start.column > 0 {
22552        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22553    } else {
22554        MultiBufferRow(selection.start.row)
22555    }
22556}
22557
22558fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22559    if next_selection.end.column > 0 || next_selection.is_empty() {
22560        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22561    } else {
22562        MultiBufferRow(next_selection.end.row)
22563    }
22564}
22565
22566impl EditorSnapshot {
22567    pub fn remote_selections_in_range<'a>(
22568        &'a self,
22569        range: &'a Range<Anchor>,
22570        collaboration_hub: &dyn CollaborationHub,
22571        cx: &'a App,
22572    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22573        let participant_names = collaboration_hub.user_names(cx);
22574        let participant_indices = collaboration_hub.user_participant_indices(cx);
22575        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22576        let collaborators_by_replica_id = collaborators_by_peer_id
22577            .values()
22578            .map(|collaborator| (collaborator.replica_id, collaborator))
22579            .collect::<HashMap<_, _>>();
22580        self.buffer_snapshot
22581            .selections_in_range(range, false)
22582            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22583                if replica_id == AGENT_REPLICA_ID {
22584                    Some(RemoteSelection {
22585                        replica_id,
22586                        selection,
22587                        cursor_shape,
22588                        line_mode,
22589                        collaborator_id: CollaboratorId::Agent,
22590                        user_name: Some("Agent".into()),
22591                        color: cx.theme().players().agent(),
22592                    })
22593                } else {
22594                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22595                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22596                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22597                    Some(RemoteSelection {
22598                        replica_id,
22599                        selection,
22600                        cursor_shape,
22601                        line_mode,
22602                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22603                        user_name,
22604                        color: if let Some(index) = participant_index {
22605                            cx.theme().players().color_for_participant(index.0)
22606                        } else {
22607                            cx.theme().players().absent()
22608                        },
22609                    })
22610                }
22611            })
22612    }
22613
22614    pub fn hunks_for_ranges(
22615        &self,
22616        ranges: impl IntoIterator<Item = Range<Point>>,
22617    ) -> Vec<MultiBufferDiffHunk> {
22618        let mut hunks = Vec::new();
22619        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22620            HashMap::default();
22621        for query_range in ranges {
22622            let query_rows =
22623                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22624            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22625                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22626            ) {
22627                // Include deleted hunks that are adjacent to the query range, because
22628                // otherwise they would be missed.
22629                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22630                if hunk.status().is_deleted() {
22631                    intersects_range |= hunk.row_range.start == query_rows.end;
22632                    intersects_range |= hunk.row_range.end == query_rows.start;
22633                }
22634                if intersects_range {
22635                    if !processed_buffer_rows
22636                        .entry(hunk.buffer_id)
22637                        .or_default()
22638                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22639                    {
22640                        continue;
22641                    }
22642                    hunks.push(hunk);
22643                }
22644            }
22645        }
22646
22647        hunks
22648    }
22649
22650    fn display_diff_hunks_for_rows<'a>(
22651        &'a self,
22652        display_rows: Range<DisplayRow>,
22653        folded_buffers: &'a HashSet<BufferId>,
22654    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22655        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22656        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22657
22658        self.buffer_snapshot
22659            .diff_hunks_in_range(buffer_start..buffer_end)
22660            .filter_map(|hunk| {
22661                if folded_buffers.contains(&hunk.buffer_id) {
22662                    return None;
22663                }
22664
22665                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22666                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22667
22668                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22669                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22670
22671                let display_hunk = if hunk_display_start.column() != 0 {
22672                    DisplayDiffHunk::Folded {
22673                        display_row: hunk_display_start.row(),
22674                    }
22675                } else {
22676                    let mut end_row = hunk_display_end.row();
22677                    if hunk_display_end.column() > 0 {
22678                        end_row.0 += 1;
22679                    }
22680                    let is_created_file = hunk.is_created_file();
22681                    DisplayDiffHunk::Unfolded {
22682                        status: hunk.status(),
22683                        diff_base_byte_range: hunk.diff_base_byte_range,
22684                        display_row_range: hunk_display_start.row()..end_row,
22685                        multi_buffer_range: Anchor::range_in_buffer(
22686                            hunk.excerpt_id,
22687                            hunk.buffer_id,
22688                            hunk.buffer_range,
22689                        ),
22690                        is_created_file,
22691                    }
22692                };
22693
22694                Some(display_hunk)
22695            })
22696    }
22697
22698    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22699        self.display_snapshot.buffer_snapshot.language_at(position)
22700    }
22701
22702    pub fn is_focused(&self) -> bool {
22703        self.is_focused
22704    }
22705
22706    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22707        self.placeholder_text.as_ref()
22708    }
22709
22710    pub fn scroll_position(&self) -> gpui::Point<f32> {
22711        self.scroll_anchor.scroll_position(&self.display_snapshot)
22712    }
22713
22714    fn gutter_dimensions(
22715        &self,
22716        font_id: FontId,
22717        font_size: Pixels,
22718        max_line_number_width: Pixels,
22719        cx: &App,
22720    ) -> Option<GutterDimensions> {
22721        if !self.show_gutter {
22722            return None;
22723        }
22724
22725        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22726        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22727
22728        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22729            matches!(
22730                ProjectSettings::get_global(cx).git.git_gutter,
22731                Some(GitGutterSetting::TrackedFiles)
22732            )
22733        });
22734        let gutter_settings = EditorSettings::get_global(cx).gutter;
22735        let show_line_numbers = self
22736            .show_line_numbers
22737            .unwrap_or(gutter_settings.line_numbers);
22738        let line_gutter_width = if show_line_numbers {
22739            // Avoid flicker-like gutter resizes when the line number gains another digit by
22740            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22741            let min_width_for_number_on_gutter =
22742                ch_advance * gutter_settings.min_line_number_digits as f32;
22743            max_line_number_width.max(min_width_for_number_on_gutter)
22744        } else {
22745            0.0.into()
22746        };
22747
22748        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22749        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22750
22751        let git_blame_entries_width =
22752            self.git_blame_gutter_max_author_length
22753                .map(|max_author_length| {
22754                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22755                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22756
22757                    /// The number of characters to dedicate to gaps and margins.
22758                    const SPACING_WIDTH: usize = 4;
22759
22760                    let max_char_count = max_author_length.min(renderer.max_author_length())
22761                        + ::git::SHORT_SHA_LENGTH
22762                        + MAX_RELATIVE_TIMESTAMP.len()
22763                        + SPACING_WIDTH;
22764
22765                    ch_advance * max_char_count
22766                });
22767
22768        let is_singleton = self.buffer_snapshot.is_singleton();
22769
22770        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22771        left_padding += if !is_singleton {
22772            ch_width * 4.0
22773        } else if show_runnables || show_breakpoints {
22774            ch_width * 3.0
22775        } else if show_git_gutter && show_line_numbers {
22776            ch_width * 2.0
22777        } else if show_git_gutter || show_line_numbers {
22778            ch_width
22779        } else {
22780            px(0.)
22781        };
22782
22783        let shows_folds = is_singleton && gutter_settings.folds;
22784
22785        let right_padding = if shows_folds && show_line_numbers {
22786            ch_width * 4.0
22787        } else if shows_folds || (!is_singleton && show_line_numbers) {
22788            ch_width * 3.0
22789        } else if show_line_numbers {
22790            ch_width
22791        } else {
22792            px(0.)
22793        };
22794
22795        Some(GutterDimensions {
22796            left_padding,
22797            right_padding,
22798            width: line_gutter_width + left_padding + right_padding,
22799            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22800            git_blame_entries_width,
22801        })
22802    }
22803
22804    pub fn render_crease_toggle(
22805        &self,
22806        buffer_row: MultiBufferRow,
22807        row_contains_cursor: bool,
22808        editor: Entity<Editor>,
22809        window: &mut Window,
22810        cx: &mut App,
22811    ) -> Option<AnyElement> {
22812        let folded = self.is_line_folded(buffer_row);
22813        let mut is_foldable = false;
22814
22815        if let Some(crease) = self
22816            .crease_snapshot
22817            .query_row(buffer_row, &self.buffer_snapshot)
22818        {
22819            is_foldable = true;
22820            match crease {
22821                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22822                    if let Some(render_toggle) = render_toggle {
22823                        let toggle_callback =
22824                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22825                                if folded {
22826                                    editor.update(cx, |editor, cx| {
22827                                        editor.fold_at(buffer_row, window, cx)
22828                                    });
22829                                } else {
22830                                    editor.update(cx, |editor, cx| {
22831                                        editor.unfold_at(buffer_row, window, cx)
22832                                    });
22833                                }
22834                            });
22835                        return Some((render_toggle)(
22836                            buffer_row,
22837                            folded,
22838                            toggle_callback,
22839                            window,
22840                            cx,
22841                        ));
22842                    }
22843                }
22844            }
22845        }
22846
22847        is_foldable |= self.starts_indent(buffer_row);
22848
22849        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22850            Some(
22851                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22852                    .toggle_state(folded)
22853                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22854                        if folded {
22855                            this.unfold_at(buffer_row, window, cx);
22856                        } else {
22857                            this.fold_at(buffer_row, window, cx);
22858                        }
22859                    }))
22860                    .into_any_element(),
22861            )
22862        } else {
22863            None
22864        }
22865    }
22866
22867    pub fn render_crease_trailer(
22868        &self,
22869        buffer_row: MultiBufferRow,
22870        window: &mut Window,
22871        cx: &mut App,
22872    ) -> Option<AnyElement> {
22873        let folded = self.is_line_folded(buffer_row);
22874        if let Crease::Inline { render_trailer, .. } = self
22875            .crease_snapshot
22876            .query_row(buffer_row, &self.buffer_snapshot)?
22877        {
22878            let render_trailer = render_trailer.as_ref()?;
22879            Some(render_trailer(buffer_row, folded, window, cx))
22880        } else {
22881            None
22882        }
22883    }
22884}
22885
22886impl Deref for EditorSnapshot {
22887    type Target = DisplaySnapshot;
22888
22889    fn deref(&self) -> &Self::Target {
22890        &self.display_snapshot
22891    }
22892}
22893
22894#[derive(Clone, Debug, PartialEq, Eq)]
22895pub enum EditorEvent {
22896    InputIgnored {
22897        text: Arc<str>,
22898    },
22899    InputHandled {
22900        utf16_range_to_replace: Option<Range<isize>>,
22901        text: Arc<str>,
22902    },
22903    ExcerptsAdded {
22904        buffer: Entity<Buffer>,
22905        predecessor: ExcerptId,
22906        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22907    },
22908    ExcerptsRemoved {
22909        ids: Vec<ExcerptId>,
22910        removed_buffer_ids: Vec<BufferId>,
22911    },
22912    BufferFoldToggled {
22913        ids: Vec<ExcerptId>,
22914        folded: bool,
22915    },
22916    ExcerptsEdited {
22917        ids: Vec<ExcerptId>,
22918    },
22919    ExcerptsExpanded {
22920        ids: Vec<ExcerptId>,
22921    },
22922    BufferEdited,
22923    Edited {
22924        transaction_id: clock::Lamport,
22925    },
22926    Reparsed(BufferId),
22927    Focused,
22928    FocusedIn,
22929    Blurred,
22930    DirtyChanged,
22931    Saved,
22932    TitleChanged,
22933    DiffBaseChanged,
22934    SelectionsChanged {
22935        local: bool,
22936    },
22937    ScrollPositionChanged {
22938        local: bool,
22939        autoscroll: bool,
22940    },
22941    Closed,
22942    TransactionUndone {
22943        transaction_id: clock::Lamport,
22944    },
22945    TransactionBegun {
22946        transaction_id: clock::Lamport,
22947    },
22948    Reloaded,
22949    CursorShapeChanged,
22950    BreadcrumbsChanged,
22951    PushedToNavHistory {
22952        anchor: Anchor,
22953        is_deactivate: bool,
22954    },
22955}
22956
22957impl EventEmitter<EditorEvent> for Editor {}
22958
22959impl Focusable for Editor {
22960    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22961        self.focus_handle.clone()
22962    }
22963}
22964
22965impl Render for Editor {
22966    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22967        let settings = ThemeSettings::get_global(cx);
22968
22969        let mut text_style = match self.mode {
22970            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
22971                color: cx.theme().colors().editor_foreground,
22972                font_family: settings.ui_font.family.clone(),
22973                font_features: settings.ui_font.features.clone(),
22974                font_fallbacks: settings.ui_font.fallbacks.clone(),
22975                font_size: rems(0.875).into(),
22976                font_weight: settings.ui_font.weight,
22977                line_height: relative(settings.buffer_line_height.value()),
22978                ..Default::default()
22979            },
22980            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22981                color: cx.theme().colors().editor_foreground,
22982                font_family: settings.buffer_font.family.clone(),
22983                font_features: settings.buffer_font.features.clone(),
22984                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22985                font_size: settings.buffer_font_size(cx).into(),
22986                font_weight: settings.buffer_font.weight,
22987                line_height: relative(settings.buffer_line_height.value()),
22988                ..Default::default()
22989            },
22990        };
22991        if let Some(text_style_refinement) = &self.text_style_refinement {
22992            text_style.refine(text_style_refinement)
22993        }
22994
22995        let background = match self.mode {
22996            EditorMode::SingleLine => cx.theme().system().transparent,
22997            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22998            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22999            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23000        };
23001
23002        EditorElement::new(
23003            &cx.entity(),
23004            EditorStyle {
23005                background,
23006                border: cx.theme().colors().border,
23007                local_player: cx.theme().players().local(),
23008                text: text_style,
23009                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23010                syntax: cx.theme().syntax().clone(),
23011                status: cx.theme().status().clone(),
23012                inlay_hints_style: make_inlay_hints_style(cx),
23013                edit_prediction_styles: make_suggestion_styles(cx),
23014                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23015                show_underlines: self.diagnostics_enabled(),
23016            },
23017        )
23018    }
23019}
23020
23021impl EntityInputHandler for Editor {
23022    fn text_for_range(
23023        &mut self,
23024        range_utf16: Range<usize>,
23025        adjusted_range: &mut Option<Range<usize>>,
23026        _: &mut Window,
23027        cx: &mut Context<Self>,
23028    ) -> Option<String> {
23029        let snapshot = self.buffer.read(cx).read(cx);
23030        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23031        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23032        if (start.0..end.0) != range_utf16 {
23033            adjusted_range.replace(start.0..end.0);
23034        }
23035        Some(snapshot.text_for_range(start..end).collect())
23036    }
23037
23038    fn selected_text_range(
23039        &mut self,
23040        ignore_disabled_input: bool,
23041        _: &mut Window,
23042        cx: &mut Context<Self>,
23043    ) -> Option<UTF16Selection> {
23044        // Prevent the IME menu from appearing when holding down an alphabetic key
23045        // while input is disabled.
23046        if !ignore_disabled_input && !self.input_enabled {
23047            return None;
23048        }
23049
23050        let selection = self.selections.newest::<OffsetUtf16>(cx);
23051        let range = selection.range();
23052
23053        Some(UTF16Selection {
23054            range: range.start.0..range.end.0,
23055            reversed: selection.reversed,
23056        })
23057    }
23058
23059    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23060        let snapshot = self.buffer.read(cx).read(cx);
23061        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23062        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23063    }
23064
23065    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23066        self.clear_highlights::<InputComposition>(cx);
23067        self.ime_transaction.take();
23068    }
23069
23070    fn replace_text_in_range(
23071        &mut self,
23072        range_utf16: Option<Range<usize>>,
23073        text: &str,
23074        window: &mut Window,
23075        cx: &mut Context<Self>,
23076    ) {
23077        if !self.input_enabled {
23078            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23079            return;
23080        }
23081
23082        self.transact(window, cx, |this, window, cx| {
23083            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23084                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23085                Some(this.selection_replacement_ranges(range_utf16, cx))
23086            } else {
23087                this.marked_text_ranges(cx)
23088            };
23089
23090            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23091                let newest_selection_id = this.selections.newest_anchor().id;
23092                this.selections
23093                    .all::<OffsetUtf16>(cx)
23094                    .iter()
23095                    .zip(ranges_to_replace.iter())
23096                    .find_map(|(selection, range)| {
23097                        if selection.id == newest_selection_id {
23098                            Some(
23099                                (range.start.0 as isize - selection.head().0 as isize)
23100                                    ..(range.end.0 as isize - selection.head().0 as isize),
23101                            )
23102                        } else {
23103                            None
23104                        }
23105                    })
23106            });
23107
23108            cx.emit(EditorEvent::InputHandled {
23109                utf16_range_to_replace: range_to_replace,
23110                text: text.into(),
23111            });
23112
23113            if let Some(new_selected_ranges) = new_selected_ranges {
23114                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23115                    selections.select_ranges(new_selected_ranges)
23116                });
23117                this.backspace(&Default::default(), window, cx);
23118            }
23119
23120            this.handle_input(text, window, cx);
23121        });
23122
23123        if let Some(transaction) = self.ime_transaction {
23124            self.buffer.update(cx, |buffer, cx| {
23125                buffer.group_until_transaction(transaction, cx);
23126            });
23127        }
23128
23129        self.unmark_text(window, cx);
23130    }
23131
23132    fn replace_and_mark_text_in_range(
23133        &mut self,
23134        range_utf16: Option<Range<usize>>,
23135        text: &str,
23136        new_selected_range_utf16: Option<Range<usize>>,
23137        window: &mut Window,
23138        cx: &mut Context<Self>,
23139    ) {
23140        if !self.input_enabled {
23141            return;
23142        }
23143
23144        let transaction = self.transact(window, cx, |this, window, cx| {
23145            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23146                let snapshot = this.buffer.read(cx).read(cx);
23147                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23148                    for marked_range in &mut marked_ranges {
23149                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23150                        marked_range.start.0 += relative_range_utf16.start;
23151                        marked_range.start =
23152                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23153                        marked_range.end =
23154                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23155                    }
23156                }
23157                Some(marked_ranges)
23158            } else if let Some(range_utf16) = range_utf16 {
23159                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23160                Some(this.selection_replacement_ranges(range_utf16, cx))
23161            } else {
23162                None
23163            };
23164
23165            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23166                let newest_selection_id = this.selections.newest_anchor().id;
23167                this.selections
23168                    .all::<OffsetUtf16>(cx)
23169                    .iter()
23170                    .zip(ranges_to_replace.iter())
23171                    .find_map(|(selection, range)| {
23172                        if selection.id == newest_selection_id {
23173                            Some(
23174                                (range.start.0 as isize - selection.head().0 as isize)
23175                                    ..(range.end.0 as isize - selection.head().0 as isize),
23176                            )
23177                        } else {
23178                            None
23179                        }
23180                    })
23181            });
23182
23183            cx.emit(EditorEvent::InputHandled {
23184                utf16_range_to_replace: range_to_replace,
23185                text: text.into(),
23186            });
23187
23188            if let Some(ranges) = ranges_to_replace {
23189                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23190                    s.select_ranges(ranges)
23191                });
23192            }
23193
23194            let marked_ranges = {
23195                let snapshot = this.buffer.read(cx).read(cx);
23196                this.selections
23197                    .disjoint_anchors()
23198                    .iter()
23199                    .map(|selection| {
23200                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23201                    })
23202                    .collect::<Vec<_>>()
23203            };
23204
23205            if text.is_empty() {
23206                this.unmark_text(window, cx);
23207            } else {
23208                this.highlight_text::<InputComposition>(
23209                    marked_ranges.clone(),
23210                    HighlightStyle {
23211                        underline: Some(UnderlineStyle {
23212                            thickness: px(1.),
23213                            color: None,
23214                            wavy: false,
23215                        }),
23216                        ..Default::default()
23217                    },
23218                    cx,
23219                );
23220            }
23221
23222            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23223            let use_autoclose = this.use_autoclose;
23224            let use_auto_surround = this.use_auto_surround;
23225            this.set_use_autoclose(false);
23226            this.set_use_auto_surround(false);
23227            this.handle_input(text, window, cx);
23228            this.set_use_autoclose(use_autoclose);
23229            this.set_use_auto_surround(use_auto_surround);
23230
23231            if let Some(new_selected_range) = new_selected_range_utf16 {
23232                let snapshot = this.buffer.read(cx).read(cx);
23233                let new_selected_ranges = marked_ranges
23234                    .into_iter()
23235                    .map(|marked_range| {
23236                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23237                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23238                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23239                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23240                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23241                    })
23242                    .collect::<Vec<_>>();
23243
23244                drop(snapshot);
23245                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23246                    selections.select_ranges(new_selected_ranges)
23247                });
23248            }
23249        });
23250
23251        self.ime_transaction = self.ime_transaction.or(transaction);
23252        if let Some(transaction) = self.ime_transaction {
23253            self.buffer.update(cx, |buffer, cx| {
23254                buffer.group_until_transaction(transaction, cx);
23255            });
23256        }
23257
23258        if self.text_highlights::<InputComposition>(cx).is_none() {
23259            self.ime_transaction.take();
23260        }
23261    }
23262
23263    fn bounds_for_range(
23264        &mut self,
23265        range_utf16: Range<usize>,
23266        element_bounds: gpui::Bounds<Pixels>,
23267        window: &mut Window,
23268        cx: &mut Context<Self>,
23269    ) -> Option<gpui::Bounds<Pixels>> {
23270        let text_layout_details = self.text_layout_details(window);
23271        let CharacterDimensions {
23272            em_width,
23273            em_advance,
23274            line_height,
23275        } = self.character_dimensions(window);
23276
23277        let snapshot = self.snapshot(window, cx);
23278        let scroll_position = snapshot.scroll_position();
23279        let scroll_left = scroll_position.x * em_advance;
23280
23281        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23282        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23283            + self.gutter_dimensions.full_width();
23284        let y = line_height * (start.row().as_f32() - scroll_position.y);
23285
23286        Some(Bounds {
23287            origin: element_bounds.origin + point(x, y),
23288            size: size(em_width, line_height),
23289        })
23290    }
23291
23292    fn character_index_for_point(
23293        &mut self,
23294        point: gpui::Point<Pixels>,
23295        _window: &mut Window,
23296        _cx: &mut Context<Self>,
23297    ) -> Option<usize> {
23298        let position_map = self.last_position_map.as_ref()?;
23299        if !position_map.text_hitbox.contains(&point) {
23300            return None;
23301        }
23302        let display_point = position_map.point_for_position(point).previous_valid;
23303        let anchor = position_map
23304            .snapshot
23305            .display_point_to_anchor(display_point, Bias::Left);
23306        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23307        Some(utf16_offset.0)
23308    }
23309}
23310
23311trait SelectionExt {
23312    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23313    fn spanned_rows(
23314        &self,
23315        include_end_if_at_line_start: bool,
23316        map: &DisplaySnapshot,
23317    ) -> Range<MultiBufferRow>;
23318}
23319
23320impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23321    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23322        let start = self
23323            .start
23324            .to_point(&map.buffer_snapshot)
23325            .to_display_point(map);
23326        let end = self
23327            .end
23328            .to_point(&map.buffer_snapshot)
23329            .to_display_point(map);
23330        if self.reversed {
23331            end..start
23332        } else {
23333            start..end
23334        }
23335    }
23336
23337    fn spanned_rows(
23338        &self,
23339        include_end_if_at_line_start: bool,
23340        map: &DisplaySnapshot,
23341    ) -> Range<MultiBufferRow> {
23342        let start = self.start.to_point(&map.buffer_snapshot);
23343        let mut end = self.end.to_point(&map.buffer_snapshot);
23344        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23345            end.row -= 1;
23346        }
23347
23348        let buffer_start = map.prev_line_boundary(start).0;
23349        let buffer_end = map.next_line_boundary(end).0;
23350        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23351    }
23352}
23353
23354impl<T: InvalidationRegion> InvalidationStack<T> {
23355    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23356    where
23357        S: Clone + ToOffset,
23358    {
23359        while let Some(region) = self.last() {
23360            let all_selections_inside_invalidation_ranges =
23361                if selections.len() == region.ranges().len() {
23362                    selections
23363                        .iter()
23364                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23365                        .all(|(selection, invalidation_range)| {
23366                            let head = selection.head().to_offset(buffer);
23367                            invalidation_range.start <= head && invalidation_range.end >= head
23368                        })
23369                } else {
23370                    false
23371                };
23372
23373            if all_selections_inside_invalidation_ranges {
23374                break;
23375            } else {
23376                self.pop();
23377            }
23378        }
23379    }
23380}
23381
23382impl<T> Default for InvalidationStack<T> {
23383    fn default() -> Self {
23384        Self(Default::default())
23385    }
23386}
23387
23388impl<T> Deref for InvalidationStack<T> {
23389    type Target = Vec<T>;
23390
23391    fn deref(&self) -> &Self::Target {
23392        &self.0
23393    }
23394}
23395
23396impl<T> DerefMut for InvalidationStack<T> {
23397    fn deref_mut(&mut self) -> &mut Self::Target {
23398        &mut self.0
23399    }
23400}
23401
23402impl InvalidationRegion for SnippetState {
23403    fn ranges(&self) -> &[Range<Anchor>] {
23404        &self.ranges[self.active_index]
23405    }
23406}
23407
23408fn edit_prediction_edit_text(
23409    current_snapshot: &BufferSnapshot,
23410    edits: &[(Range<Anchor>, String)],
23411    edit_preview: &EditPreview,
23412    include_deletions: bool,
23413    cx: &App,
23414) -> HighlightedText {
23415    let edits = edits
23416        .iter()
23417        .map(|(anchor, text)| {
23418            (
23419                anchor.start.text_anchor..anchor.end.text_anchor,
23420                text.clone(),
23421            )
23422        })
23423        .collect::<Vec<_>>();
23424
23425    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23426}
23427
23428fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23429    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23430    // Just show the raw edit text with basic styling
23431    let mut text = String::new();
23432    let mut highlights = Vec::new();
23433
23434    let insertion_highlight_style = HighlightStyle {
23435        color: Some(cx.theme().colors().text),
23436        ..Default::default()
23437    };
23438
23439    for (_, edit_text) in edits {
23440        let start_offset = text.len();
23441        text.push_str(edit_text);
23442        let end_offset = text.len();
23443
23444        if start_offset < end_offset {
23445            highlights.push((start_offset..end_offset, insertion_highlight_style));
23446        }
23447    }
23448
23449    HighlightedText {
23450        text: text.into(),
23451        highlights,
23452    }
23453}
23454
23455pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23456    match severity {
23457        lsp::DiagnosticSeverity::ERROR => colors.error,
23458        lsp::DiagnosticSeverity::WARNING => colors.warning,
23459        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23460        lsp::DiagnosticSeverity::HINT => colors.info,
23461        _ => colors.ignored,
23462    }
23463}
23464
23465pub fn styled_runs_for_code_label<'a>(
23466    label: &'a CodeLabel,
23467    syntax_theme: &'a theme::SyntaxTheme,
23468) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23469    let fade_out = HighlightStyle {
23470        fade_out: Some(0.35),
23471        ..Default::default()
23472    };
23473
23474    let mut prev_end = label.filter_range.end;
23475    label
23476        .runs
23477        .iter()
23478        .enumerate()
23479        .flat_map(move |(ix, (range, highlight_id))| {
23480            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23481                style
23482            } else {
23483                return Default::default();
23484            };
23485            let mut muted_style = style;
23486            muted_style.highlight(fade_out);
23487
23488            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23489            if range.start >= label.filter_range.end {
23490                if range.start > prev_end {
23491                    runs.push((prev_end..range.start, fade_out));
23492                }
23493                runs.push((range.clone(), muted_style));
23494            } else if range.end <= label.filter_range.end {
23495                runs.push((range.clone(), style));
23496            } else {
23497                runs.push((range.start..label.filter_range.end, style));
23498                runs.push((label.filter_range.end..range.end, muted_style));
23499            }
23500            prev_end = cmp::max(prev_end, range.end);
23501
23502            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23503                runs.push((prev_end..label.text.len(), fade_out));
23504            }
23505
23506            runs
23507        })
23508}
23509
23510pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23511    let mut prev_index = 0;
23512    let mut prev_codepoint: Option<char> = None;
23513    text.char_indices()
23514        .chain([(text.len(), '\0')])
23515        .filter_map(move |(index, codepoint)| {
23516            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23517            let is_boundary = index == text.len()
23518                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23519                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23520            if is_boundary {
23521                let chunk = &text[prev_index..index];
23522                prev_index = index;
23523                Some(chunk)
23524            } else {
23525                None
23526            }
23527        })
23528}
23529
23530pub trait RangeToAnchorExt: Sized {
23531    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23532
23533    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23534        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23535        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23536    }
23537}
23538
23539impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23540    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23541        let start_offset = self.start.to_offset(snapshot);
23542        let end_offset = self.end.to_offset(snapshot);
23543        if start_offset == end_offset {
23544            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23545        } else {
23546            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23547        }
23548    }
23549}
23550
23551pub trait RowExt {
23552    fn as_f32(&self) -> f32;
23553
23554    fn next_row(&self) -> Self;
23555
23556    fn previous_row(&self) -> Self;
23557
23558    fn minus(&self, other: Self) -> u32;
23559}
23560
23561impl RowExt for DisplayRow {
23562    fn as_f32(&self) -> f32 {
23563        self.0 as f32
23564    }
23565
23566    fn next_row(&self) -> Self {
23567        Self(self.0 + 1)
23568    }
23569
23570    fn previous_row(&self) -> Self {
23571        Self(self.0.saturating_sub(1))
23572    }
23573
23574    fn minus(&self, other: Self) -> u32 {
23575        self.0 - other.0
23576    }
23577}
23578
23579impl RowExt for MultiBufferRow {
23580    fn as_f32(&self) -> f32 {
23581        self.0 as f32
23582    }
23583
23584    fn next_row(&self) -> Self {
23585        Self(self.0 + 1)
23586    }
23587
23588    fn previous_row(&self) -> Self {
23589        Self(self.0.saturating_sub(1))
23590    }
23591
23592    fn minus(&self, other: Self) -> u32 {
23593        self.0 - other.0
23594    }
23595}
23596
23597trait RowRangeExt {
23598    type Row;
23599
23600    fn len(&self) -> usize;
23601
23602    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23603}
23604
23605impl RowRangeExt for Range<MultiBufferRow> {
23606    type Row = MultiBufferRow;
23607
23608    fn len(&self) -> usize {
23609        (self.end.0 - self.start.0) as usize
23610    }
23611
23612    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23613        (self.start.0..self.end.0).map(MultiBufferRow)
23614    }
23615}
23616
23617impl RowRangeExt for Range<DisplayRow> {
23618    type Row = DisplayRow;
23619
23620    fn len(&self) -> usize {
23621        (self.end.0 - self.start.0) as usize
23622    }
23623
23624    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23625        (self.start.0..self.end.0).map(DisplayRow)
23626    }
23627}
23628
23629/// If select range has more than one line, we
23630/// just point the cursor to range.start.
23631fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23632    if range.start.row == range.end.row {
23633        range
23634    } else {
23635        range.start..range.start
23636    }
23637}
23638pub struct KillRing(ClipboardItem);
23639impl Global for KillRing {}
23640
23641const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23642
23643enum BreakpointPromptEditAction {
23644    Log,
23645    Condition,
23646    HitCondition,
23647}
23648
23649struct BreakpointPromptEditor {
23650    pub(crate) prompt: Entity<Editor>,
23651    editor: WeakEntity<Editor>,
23652    breakpoint_anchor: Anchor,
23653    breakpoint: Breakpoint,
23654    edit_action: BreakpointPromptEditAction,
23655    block_ids: HashSet<CustomBlockId>,
23656    editor_margins: Arc<Mutex<EditorMargins>>,
23657    _subscriptions: Vec<Subscription>,
23658}
23659
23660impl BreakpointPromptEditor {
23661    const MAX_LINES: u8 = 4;
23662
23663    fn new(
23664        editor: WeakEntity<Editor>,
23665        breakpoint_anchor: Anchor,
23666        breakpoint: Breakpoint,
23667        edit_action: BreakpointPromptEditAction,
23668        window: &mut Window,
23669        cx: &mut Context<Self>,
23670    ) -> Self {
23671        let base_text = match edit_action {
23672            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23673            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23674            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23675        }
23676        .map(|msg| msg.to_string())
23677        .unwrap_or_default();
23678
23679        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23680        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23681
23682        let prompt = cx.new(|cx| {
23683            let mut prompt = Editor::new(
23684                EditorMode::AutoHeight {
23685                    min_lines: 1,
23686                    max_lines: Some(Self::MAX_LINES as usize),
23687                },
23688                buffer,
23689                None,
23690                window,
23691                cx,
23692            );
23693            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23694            prompt.set_show_cursor_when_unfocused(false, cx);
23695            prompt.set_placeholder_text(
23696                match edit_action {
23697                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23698                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23699                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23700                },
23701                cx,
23702            );
23703
23704            prompt
23705        });
23706
23707        Self {
23708            prompt,
23709            editor,
23710            breakpoint_anchor,
23711            breakpoint,
23712            edit_action,
23713            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23714            block_ids: Default::default(),
23715            _subscriptions: vec![],
23716        }
23717    }
23718
23719    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23720        self.block_ids.extend(block_ids)
23721    }
23722
23723    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23724        if let Some(editor) = self.editor.upgrade() {
23725            let message = self
23726                .prompt
23727                .read(cx)
23728                .buffer
23729                .read(cx)
23730                .as_singleton()
23731                .expect("A multi buffer in breakpoint prompt isn't possible")
23732                .read(cx)
23733                .as_rope()
23734                .to_string();
23735
23736            editor.update(cx, |editor, cx| {
23737                editor.edit_breakpoint_at_anchor(
23738                    self.breakpoint_anchor,
23739                    self.breakpoint.clone(),
23740                    match self.edit_action {
23741                        BreakpointPromptEditAction::Log => {
23742                            BreakpointEditAction::EditLogMessage(message.into())
23743                        }
23744                        BreakpointPromptEditAction::Condition => {
23745                            BreakpointEditAction::EditCondition(message.into())
23746                        }
23747                        BreakpointPromptEditAction::HitCondition => {
23748                            BreakpointEditAction::EditHitCondition(message.into())
23749                        }
23750                    },
23751                    cx,
23752                );
23753
23754                editor.remove_blocks(self.block_ids.clone(), None, cx);
23755                cx.focus_self(window);
23756            });
23757        }
23758    }
23759
23760    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23761        self.editor
23762            .update(cx, |editor, cx| {
23763                editor.remove_blocks(self.block_ids.clone(), None, cx);
23764                window.focus(&editor.focus_handle);
23765            })
23766            .log_err();
23767    }
23768
23769    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23770        let settings = ThemeSettings::get_global(cx);
23771        let text_style = TextStyle {
23772            color: if self.prompt.read(cx).read_only(cx) {
23773                cx.theme().colors().text_disabled
23774            } else {
23775                cx.theme().colors().text
23776            },
23777            font_family: settings.buffer_font.family.clone(),
23778            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23779            font_size: settings.buffer_font_size(cx).into(),
23780            font_weight: settings.buffer_font.weight,
23781            line_height: relative(settings.buffer_line_height.value()),
23782            ..Default::default()
23783        };
23784        EditorElement::new(
23785            &self.prompt,
23786            EditorStyle {
23787                background: cx.theme().colors().editor_background,
23788                local_player: cx.theme().players().local(),
23789                text: text_style,
23790                ..Default::default()
23791            },
23792        )
23793    }
23794}
23795
23796impl Render for BreakpointPromptEditor {
23797    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23798        let editor_margins = *self.editor_margins.lock();
23799        let gutter_dimensions = editor_margins.gutter;
23800        h_flex()
23801            .key_context("Editor")
23802            .bg(cx.theme().colors().editor_background)
23803            .border_y_1()
23804            .border_color(cx.theme().status().info_border)
23805            .size_full()
23806            .py(window.line_height() / 2.5)
23807            .on_action(cx.listener(Self::confirm))
23808            .on_action(cx.listener(Self::cancel))
23809            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23810            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23811    }
23812}
23813
23814impl Focusable for BreakpointPromptEditor {
23815    fn focus_handle(&self, cx: &App) -> FocusHandle {
23816        self.prompt.focus_handle(cx)
23817    }
23818}
23819
23820fn all_edits_insertions_or_deletions(
23821    edits: &Vec<(Range<Anchor>, String)>,
23822    snapshot: &MultiBufferSnapshot,
23823) -> bool {
23824    let mut all_insertions = true;
23825    let mut all_deletions = true;
23826
23827    for (range, new_text) in edits.iter() {
23828        let range_is_empty = range.to_offset(snapshot).is_empty();
23829        let text_is_empty = new_text.is_empty();
23830
23831        if range_is_empty != text_is_empty {
23832            if range_is_empty {
23833                all_deletions = false;
23834            } else {
23835                all_insertions = false;
23836            }
23837        } else {
23838            return false;
23839        }
23840
23841        if !all_insertions && !all_deletions {
23842            return false;
23843        }
23844    }
23845    all_insertions || all_deletions
23846}
23847
23848struct MissingEditPredictionKeybindingTooltip;
23849
23850impl Render for MissingEditPredictionKeybindingTooltip {
23851    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23852        ui::tooltip_container(window, cx, |container, _, cx| {
23853            container
23854                .flex_shrink_0()
23855                .max_w_80()
23856                .min_h(rems_from_px(124.))
23857                .justify_between()
23858                .child(
23859                    v_flex()
23860                        .flex_1()
23861                        .text_ui_sm(cx)
23862                        .child(Label::new("Conflict with Accept Keybinding"))
23863                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23864                )
23865                .child(
23866                    h_flex()
23867                        .pb_1()
23868                        .gap_1()
23869                        .items_end()
23870                        .w_full()
23871                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23872                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23873                        }))
23874                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23875                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23876                        })),
23877                )
23878        })
23879    }
23880}
23881
23882#[derive(Debug, Clone, Copy, PartialEq)]
23883pub struct LineHighlight {
23884    pub background: Background,
23885    pub border: Option<gpui::Hsla>,
23886    pub include_gutter: bool,
23887    pub type_id: Option<TypeId>,
23888}
23889
23890struct LineManipulationResult {
23891    pub new_text: String,
23892    pub line_count_before: usize,
23893    pub line_count_after: usize,
23894}
23895
23896fn render_diff_hunk_controls(
23897    row: u32,
23898    status: &DiffHunkStatus,
23899    hunk_range: Range<Anchor>,
23900    is_created_file: bool,
23901    line_height: Pixels,
23902    editor: &Entity<Editor>,
23903    _window: &mut Window,
23904    cx: &mut App,
23905) -> AnyElement {
23906    h_flex()
23907        .h(line_height)
23908        .mr_1()
23909        .gap_1()
23910        .px_0p5()
23911        .pb_1()
23912        .border_x_1()
23913        .border_b_1()
23914        .border_color(cx.theme().colors().border_variant)
23915        .rounded_b_lg()
23916        .bg(cx.theme().colors().editor_background)
23917        .gap_1()
23918        .block_mouse_except_scroll()
23919        .shadow_md()
23920        .child(if status.has_secondary_hunk() {
23921            Button::new(("stage", row as u64), "Stage")
23922                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23923                .tooltip({
23924                    let focus_handle = editor.focus_handle(cx);
23925                    move |window, cx| {
23926                        Tooltip::for_action_in(
23927                            "Stage Hunk",
23928                            &::git::ToggleStaged,
23929                            &focus_handle,
23930                            window,
23931                            cx,
23932                        )
23933                    }
23934                })
23935                .on_click({
23936                    let editor = editor.clone();
23937                    move |_event, _window, cx| {
23938                        editor.update(cx, |editor, cx| {
23939                            editor.stage_or_unstage_diff_hunks(
23940                                true,
23941                                vec![hunk_range.start..hunk_range.start],
23942                                cx,
23943                            );
23944                        });
23945                    }
23946                })
23947        } else {
23948            Button::new(("unstage", row as u64), "Unstage")
23949                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23950                .tooltip({
23951                    let focus_handle = editor.focus_handle(cx);
23952                    move |window, cx| {
23953                        Tooltip::for_action_in(
23954                            "Unstage Hunk",
23955                            &::git::ToggleStaged,
23956                            &focus_handle,
23957                            window,
23958                            cx,
23959                        )
23960                    }
23961                })
23962                .on_click({
23963                    let editor = editor.clone();
23964                    move |_event, _window, cx| {
23965                        editor.update(cx, |editor, cx| {
23966                            editor.stage_or_unstage_diff_hunks(
23967                                false,
23968                                vec![hunk_range.start..hunk_range.start],
23969                                cx,
23970                            );
23971                        });
23972                    }
23973                })
23974        })
23975        .child(
23976            Button::new(("restore", row as u64), "Restore")
23977                .tooltip({
23978                    let focus_handle = editor.focus_handle(cx);
23979                    move |window, cx| {
23980                        Tooltip::for_action_in(
23981                            "Restore Hunk",
23982                            &::git::Restore,
23983                            &focus_handle,
23984                            window,
23985                            cx,
23986                        )
23987                    }
23988                })
23989                .on_click({
23990                    let editor = editor.clone();
23991                    move |_event, window, cx| {
23992                        editor.update(cx, |editor, cx| {
23993                            let snapshot = editor.snapshot(window, cx);
23994                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23995                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23996                        });
23997                    }
23998                })
23999                .disabled(is_created_file),
24000        )
24001        .when(
24002            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24003            |el| {
24004                el.child(
24005                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24006                        .shape(IconButtonShape::Square)
24007                        .icon_size(IconSize::Small)
24008                        // .disabled(!has_multiple_hunks)
24009                        .tooltip({
24010                            let focus_handle = editor.focus_handle(cx);
24011                            move |window, cx| {
24012                                Tooltip::for_action_in(
24013                                    "Next Hunk",
24014                                    &GoToHunk,
24015                                    &focus_handle,
24016                                    window,
24017                                    cx,
24018                                )
24019                            }
24020                        })
24021                        .on_click({
24022                            let editor = editor.clone();
24023                            move |_event, window, cx| {
24024                                editor.update(cx, |editor, cx| {
24025                                    let snapshot = editor.snapshot(window, cx);
24026                                    let position =
24027                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24028                                    editor.go_to_hunk_before_or_after_position(
24029                                        &snapshot,
24030                                        position,
24031                                        Direction::Next,
24032                                        window,
24033                                        cx,
24034                                    );
24035                                    editor.expand_selected_diff_hunks(cx);
24036                                });
24037                            }
24038                        }),
24039                )
24040                .child(
24041                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24042                        .shape(IconButtonShape::Square)
24043                        .icon_size(IconSize::Small)
24044                        // .disabled(!has_multiple_hunks)
24045                        .tooltip({
24046                            let focus_handle = editor.focus_handle(cx);
24047                            move |window, cx| {
24048                                Tooltip::for_action_in(
24049                                    "Previous Hunk",
24050                                    &GoToPreviousHunk,
24051                                    &focus_handle,
24052                                    window,
24053                                    cx,
24054                                )
24055                            }
24056                        })
24057                        .on_click({
24058                            let editor = editor.clone();
24059                            move |_event, window, cx| {
24060                                editor.update(cx, |editor, cx| {
24061                                    let snapshot = editor.snapshot(window, cx);
24062                                    let point =
24063                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24064                                    editor.go_to_hunk_before_or_after_position(
24065                                        &snapshot,
24066                                        point,
24067                                        Direction::Prev,
24068                                        window,
24069                                        cx,
24070                                    );
24071                                    editor.expand_selected_diff_hunks(cx);
24072                                });
24073                            }
24074                        }),
24075                )
24076            },
24077        )
24078        .into_any_element()
24079}
24080
24081pub fn multibuffer_context_lines(cx: &App) -> u32 {
24082    EditorSettings::try_get(cx)
24083        .map(|settings| settings.excerpt_context_lines)
24084        .unwrap_or(2)
24085        .clamp(1, 32)
24086}